java进阶07 线程的让步与阻塞与同步
前面介绍了线程的一些基本知识,现在来说下线程的让步,阻塞,和同步
先说说让步
所谓让步,就是让调用者的线程暂停,让其他线程重新竞争CPU,包括调用者。
先看看代码
package Thread; public class ThreadYield { public static void main(String[] args){ MyThread5 rthread=new MyThread5(); Thread thread1=new Thread(rthread); Thread thread2=new Thread(rthread); thread1.setName("线程1"); thread2.setName("线程2"); thread1.start(); thread2.start(); } } //通过实现接口Runnable实现 class MyThread5 implements Runnable{ public void run(){ for(int i=1;i<=30;i++){ System.out.println(Thread.currentThread().getName()+"正在执行"+i); if(i%5==0){ Thread.yield();//线程的让步 将该线程暂停 然后重新让所有线程争取CPU System.out.println("重新竞争CPU"); } } } }
我们来分析下该代码
代码中的Thread.yield()就是让步的函数,这里循环30次 当i为5的倍数的时候 让步 同时打出 重新竞争CPU的字段
那我们期待的结果就是这样的形式:
线程1正在执行1
线程1正在执行2
线程1正在执行3
线程1正在执行4
线程1正在执行5
重新竞争CPU
线程1正在执行6
线程1正在执行7
线程1正在执行8
线程1正在执行9
线程1正在执行10
重新竞争CPU
那我们来看看真正打出结果:
线程2正在执行1
线程1正在执行1
线程2正在执行2
线程1正在执行2
线程2正在执行3
线程2正在执行4
线程2正在执行5
重新竞争CPU
线程2正在执行6
线程2正在执行7
线程1正在执行3
线程2正在执行8
线程1正在执行4
线程2正在执行9
线程1正在执行5
重新竞争CPU
这可跟我们期待的值差太多了。
这是什么原因呢? 还是由于CPU的分配的问题,CPU分配是随机的,什么时候当前线程被其他线程抢去也不奇怪。
还有可能出现这种结果:
线程1正在执行5
线程2正在执行5
重新竞争CPU
重新竞争CPU
这就是当程序i=5的倍数时,运行完System.out.println(Thread.currentThread().getName()+"正在执行"+i);
该线程就被挤出去了,导致 for里面都只运行了一半.
而为了处理这种情况,提供了一种叫同步的东西:
所谓线程同步,就是在一段程序执行的过程中,无论成功还是失败,其他线程都会等待这段程序的执行完毕,才会转入其他线程
这样可以保证程序的完整性和安全性。
java里用synchronsized关键值实现
它既可以修饰代码块,又可以修饰函数。
package Thread; public class ThreadSynchronized { public static void main(String[] args){ MyThread7 rthread=new MyThread7(); Thread thread1=new Thread(rthread); Thread thread2=new Thread(rthread); thread1.setName("线程1"); thread2.setName("线程2"); thread1.start(); thread2.start(); } } //通过实现接口Runnable实现 class MyThread7 implements Runnable{ String word=new String("Word"); public void run(){ synchronized (word) { for(int i=1;i<=30;i++){ System.out.println(Thread.currentThread().getName()+"正在执行"+i); if(i%5==0){ Thread.yield();//线程的让步 将该线程暂停 然后重新让所有线程争取CPU System.out.println("重新竞争CPU"); } } } } }
输出结果:
线程1正在执行1
线程1正在执行2
线程1正在执行3
线程1正在执行4
线程1正在执行5
重新竞争CPU
线程1正在执行6
线程1正在执行7
线程1正在执行8
线程1正在执行9
线程1正在执行10
重新竞争CPU
这就达到了我们想要的结果。
最后讲到的就是线程的阻塞。
调用Thread.join()会 阻塞当前线程,直至调用者的线程执行完毕之后,才执行其他线程,相当于将CPU全部分给调用者的线程。从而达到控制线程的先后顺序
package Thread; public class ThreadJion { public static void main(String[] args){ MyThread6 rthread=new MyThread6(); Thread thread=new Thread(rthread); thread.setName("线程1"); thread.start(); try { thread.join();//阻塞当前线程 直到调用方全部执行完 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("线程阻塞出错"); } for(int i=0;i<500;i++) System.out.println("主线程正在执行"); } } //通过实现接口Runnable实现 class MyThread6 implements Runnable{ public void run(){ for(int i=0;i<10000;i++){ System.out.println(Thread.currentThread().getName()+"正在执行"+i); } } }
输出结果:
线程1正在执行9998
线程1正在执行9999
主线程正在执行
主线程正在执行
可以看出新开的线程和主线程不会出现互相交替出现的时候了,因为新开线程阻塞了主线程,只有等到该线程全部执行完毕的时候,才会执行主线程
关于线程的东西就先说到这里了。