多线程之线程的状态和通信
线程调试工具:ThreadDump
线程的五种状态:

1.新建(new):
新建了一个线程对象.
2.可运行(runnable):
线程对象创建后,其他线程(比如mian线程)调用了该对象的start方法,该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权
3运行(running):
可运行状态的线程获得了cpu时间片,执行程序代码
4.阻塞(blocked):
阻塞状态是指线程因为某种原因放弃了cpu的使用权,也让出了cpu时间片,暂时停止运行,直到线程进入可运行状态,才有机会再次获得CPU 时间片转到运行状态
5.死亡(dead):
线程run main方法执行结束,或者run方法出现异常,该线程的生命周期结束,死亡线程不可复生
三种阻塞:
1.等待阻塞:
运行的线程使用的wait方法,JVM将该线程放进等待队列中
2.同步阻塞:
运行线程获取对象同步锁的时候,若该线程锁被别的线程所占用,JVM会把该线程放入锁池中
3.其他阻塞;
执行了sleep join等方法,或者发出了IO请求,当sleep超时,join等待线程终止或者超时,io处理完毕时,线程会重新转入可运行状态

1.sleep()和yield()和join()
1)sleep()方法作用:让当前线程睡眠一段时间,期间不会释放任何持有的锁。
2) yield()方法作用:让出该线程的时间片给其它线程。线程调用了yield()方法,表示放弃当前获得的CPU时间片,回到就绪状态。最后由线程调度重新选择就绪状态的线程分配CPU资源。
3)join()方法作用:暂停当前线程,等待被调用线程指向结束之后再继续执行。
线程的通信有两种方式:
1.synchronized + wait + notify+notifyAll:
四个方法都是object的方法,所以所有类都可以继承这四个方法
wait方法:
使得当前线程必须要等待,等到另一个线程调用notify或者notifyall方法.
notify,notifyAll:
会唤醒一个等待当前对象的锁的线程,而notifyAll就是唤醒所有等待锁的线程.
wait notify方法要求在调用时线程已经获得对象的锁,所以这两个方法要放在synchronized方法或者synchronized块中
sleep与wait方法的区别:sleep方法是不释放锁的,wait方法释放锁
2.lock + condition + await + signal:
都可以达到通信的效果,但是对比第一种方式:
1.locl是个类
2.执行完必须在finally里释放锁,执行前必须上锁,而且要紧跟try代码块
3.可以自己控制锁哪个线程,保证公平性
4.性能上高一些,因为大量同步
例子:
package thread_Runnable; class Printer { int i = 1; synchronized public void printEven(){ for(;i<=100;) { if (i % 2 == 1) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println(Thread.currentThread().getName() + " is printting i: " + i++); notify(); } } } synchronized public void printOdd(){ for(; i<=100; ) { if (i % 2 == 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println(Thread.currentThread().getName() + " is printting i: " + i++); notify(); } } } } // 必须要创建两个类 去执行对应的方法,才能保证唤醒另一个线程 要实现两个线程分别打印,所以有如下代码: class PrintEven implements Runnable{ Printer printer; public PrintEven(Printer printer){ this.printer = printer; } public void run() { printer.printEven(); } } class PrintOdd implements Runnable { Printer printer; public PrintOdd(Printer printer){ this.printer = printer; } public void run() { printer.printOdd(); } } //主函数: 把printer作为对象传入 class main{ public static void main(String[] args){ Printer printer = new Printer(); Runnable printOdd = new PrintOdd(printer); Thread threadOdd = new Thread(printOdd, "thread1"); Runnable printEven = new PrintEven(printer); Thread threadEven = new Thread(printEven, "thread2"); threadOdd.start(); threadEven.start(); } }
注意:
◆调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {……} 代码段内。
◆调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {……} 代码段内唤醒A.
◆当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
◆如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
◆obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
◆当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
原文链接:https://blog.csdn.net/weixin_43326401/article/details/104107084

浙公网安备 33010602011771号