线程间的调度和状态转换关系

线程的调度

线程的调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种

协同式线程调度

线程执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切到另一个线程上。

协调式多线程的最大的好处是实现简单,而且由于线程要把自己的事情干完之后才会进行线程切换,切换操作对线程自己是可知的,所以没有什么线程同步的问题。

缺点也很明显:线程执行时间不可控制,如果有一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。

抢占式线程调度

每个线程将由系统分配执行时间,线程的切换不由线程本身来决定(JAVA中,Thread.yield()可以让出执行时间)

虽然java线程调度是系统自动完成的,但是我们还是可以"建议"系统给某些线程多一些执行时间,这项操作可以通过设置线程优先级完成(Thread.MIN_PRIORITY致Thread.Thread.MAX_PRIORITY)

线程状态转换关系

线程状态图有助于我们记忆线程一些方法。

java语言定义了5种线程状态,在任意一个时间点,一个线程只能有且只有其中的一种状态,这5种状态分别如下。

1)新建(New):

创建后尚未启动的线程处于这种状态。

2)运行(Runable):

Runable包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能等待着CPU为它分配执行时间,所谓的Ready(就绪)状态 指的在CPU的等待队列里面。

Thread.yield()会从Running 状态—>Ready状态。yield(): 当前线程会做出让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示

3)等待(Waiting):

无限期等待(Waiting):

处于这种状态的线程不会被分配CPU执行时间,它们要等待被其他线程显式地唤醒。以下方法会让线程陷入无限期的等待状态

   没有设置Timeout参数的Object.wait()方法

wait():的目的是为了多个线程抢资源的时候,当前线程把资源让出来

如果没有锁,就不存在两个线程抢资源的情况,也就没有必要把资源让出来,两个线程早就一起跑了 这也很好解释了为什么wait方法synchronized关键字连用。

   没有设置Timeout参数的Thread.join()方法

join():合并某个线程,他调用此方法的线程(别的线程)合并到当前线程上来。等待调用此方法的线程执行完了,当前线程才开始继续执行(经常用于等待另外一个线程的结束,有点像方法调用)。

   LockSupport.park()方法 参考LockSupport实现生产者与消费者

限期等待(Time Waiting):

处于这种状态的线程也不会被CPU分配执行时间,不过无须等待被其他线程显式的唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待的状态

   Thread.sleep()方法

sleep():的过程之中 如果对当前对象加锁了(可以不加),不会释放当前对象的锁。

   设置了Timeout的Object.wait()方法

   设置了TImeout的Thread.join()方法

   LockSupport.parkBanos()方法和LockSupport.parkUntil()方法

4)阻塞(Blocked): 

"阻塞状态"与"等待状态"的区别是:阻塞状态在等待着获取到一个排他锁,等待着一个进入同步代码块的锁;而等待状态则是等待一段时间,或者唤醒动作的发生。

5)结束(Terminated):

已经终止线程的状态,线程已经结束执行。

上述5种状态在遇到特定事件发生的时候会互相转换,它们之间的关系如下图所示:

原文地址:https://www.cnblogs.com/ssskkk/p/12840205.html