主要这几天在看些线程相关的知识,想着就把自己理解的知识做一下梳理和总结。今天主要总结下线程的几个状态以及这个几个状态之间的关联和达到的必要条件,以及wait 、notify、notifyAll、sleep、join等方法的简单理解。

1.线程的状态

线程、多线程知识点总结(二)

上图所示线程的新建有三种方法继承Thread类、实现runnable接口、实现callable接口有ExecutorService回调来创建线程,主要状态:新建、就绪、运行、死亡、等待、阻塞等。针对上述的几个方法做下概述。

wait / notify / notifyAll

  • wait( ),notify( ),notifyAll( )都不属于Thread类,而是属于Object基础类,也就是每个对象都有wait( ),notify( ),notifyAll( ) 的功能,因为每个对象都有锁,锁是每个对象的基础,当然操作锁的方法也是最基础了。

  • 当需要调用以上的方法的时候,一定要对竞争资源进行加锁,如果不加锁的话,则会报 IllegalMonitorStateException 异常

  • 当想要调用wait( )进行线程等待时,必须要取得这个锁对象的控制权(对象监视器),一般是放到synchronized(obj)代码中

  • while循环里而不是if语句下使用wait,这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知

  • 调用obj.wait( )释放了obj的锁,否则其他线程也无法获得obj的锁,也就无法在synchronized(obj){ obj.notify() } 代码段内唤醒A。

  • notify( )方法只会通知等待队列中的第一个相关线程(不会通知优先级比较高的线程)

  • notifyAll( )通知所有等待该竞争资源的线程(也不会按照线程的优先级来执行)

  • 假设有三个线程执行了obj.wait( ),那么obj.notifyAll( )则能全部唤醒tread1,thread2,thread3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,tread1,thread2,thread3只有一个有机会获得锁继续执行,例如tread1,其余的需要等待thread1释放obj锁之后才能继续执行。

  • 当调用obj.notify/notifyAll后,调用线程依旧持有obj锁,因此,thread1,thread2,thread3虽被唤醒,但是仍无法获得obj锁。直到调用线程退出synchronized块,释放obj锁后,thread1,thread2,thread3中的一个才有机会获得锁继续执行

sleep

对于sleep()方法,我们首先要知道该方法是属于Thread类中的。sleep()方法导致了程序暂停执行指定的时间,让出cpu由其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。也就是说该线程调用sleep () 方法的时候仅仅是让出了 cpu 的使用权,但是当前对象的锁并未释放,对于要竞争同一对象的其他线程来说还是处于等待状态,等待该线程释放对象锁。

join

Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。注意,这里调用的join方法是没有传参的,join方法其实也可以传递一个参数给它的,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。

然而join 方法的底层是相当于对于主线程使用啦wait 和 notifyAll 方法当切仅当当前线程执行完毕,其他线程方可竞争资源详情见源码:

线程、多线程知识点总结(二)

线程、多线程知识点总结(二)

当前线程执行join() 内部调用啦wait () 方法,当前线程执行完毕JVM会执行JavaThread::exit() 方法,结束当前线程,同时会执行ensure_join() 方法,内部调用啦notifyAll() 方法,仅此而已。

如有披露或问题欢迎留言或者入群探讨

线程、多线程知识点总结(二)

相关文章: