Java 多线程相关问题记录

线程状态图:html

线程状态图说明
线程共包括如下5种状态。java

  1. **新建状态(New) **: 线程对象被建立后,就进入了新建状态。例如,Thread thread = new Thread()。
  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被建立后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
  3. 运行状态(Running) : 线程获取CPU权限进行执行。须要注意的是,线程只能从就绪状态进入到运行状态。
  4. **阻塞状态(Blocked) ** : 阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的状况分三种:
    (01) 等待阻塞 -- 经过调用线程的wait()方法,让线程等待某工做的完成。
    (02) 同步阻塞 -- 线程在获取synchronized同步锁失败(由于锁被其它线程所占用),它会进入同步阻塞状态。
    (03) 其余阻塞 -- 经过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。
  5. 死亡状态(Dead) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

1. wait(), notify(), notifyAll()等方法介绍

在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的做用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的做用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒全部的线程。app

Object类中关于等待/唤醒的API详细信息以下:
**notify() **-- 唤醒在此对象监视器上等待的单个线程。
**notifyAll() ** -- 唤醒在此对象监视器上等待的全部线程。
**wait() ** -- 让当前线程处于“等待(阻塞)状态”,“直到其余线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
**wait(long timeout) ** -- 让当前线程处于“等待(阻塞)状态”,“直到其余线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
**wait(long timeout, int nanos) **-- 让当前线程处于“等待(阻塞)状态”,“直到其余线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其余某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。函数

2. 为何notify(), wait()等函数定义在Object中,而不是Thread中

Object中的wait(), notify()等函数,和synchronized同样,会对“对象的同步锁”进行操做。spa

wait()会使“当前线程”等待,由于线程进入等待状态,因此线程应该释放它锁持有的“同步锁”,不然其它线程获取不到该“同步锁”而没法运行!
OK,线程调用wait()以后,会释放它锁持有的“同步锁”;并且,根据前面的介绍,咱们知道:等待线程能够被notify()或notifyAll()唤醒。如今,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是经过什么关联起来的?答案是:依据“对象的同步锁”。线程

负责唤醒等待线程的那个线程(咱们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),而且调用notify()或notifyAll()方法以后,才能唤醒等待线程。虽然,等待线程被唤醒;可是,它不能马上执行,由于唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”以后,等待线程才能获取到“对象的同步锁”进而继续运行。code

总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,而且每一个对象有且仅有一个!这就是为何notify(), wait()等函数定义在Object类,而不是Thread类中的缘由。htm

** 3. yield()介绍**

yield()的做用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具备相同优先级的等待线程获取执行权;可是,并不能保证在当前线程调用yield()以后,其它具备相同优先级的线程就必定能得到执行权;也有多是当前线程又进入到“运行状态”继续运行!对象

4. yield() 与 wait()的比较

咱们知道,wait()的做用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而yield()的做用是让步,它也会让当前线程离开“运行状态”。它们的区别是: (01) wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而不yield()是让线程由“运行状态”进入到“就绪状态”。 (02) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。blog

参考文献:

https://www.cnblogs.com/happy-coder/p/6587092.html