线程从创建、运行、到结束一共有五个状态:
新建状态、就绪状态、运行状态、阻塞状态、死亡状态
1、新建状态
当用new操作符 创建一个线程时, 线程还没有开始运行,此时是新建状态
2、就绪状态(start 阻塞解除、yield(礼让)、jvm切换其他线程 会进入就绪状态)
当我们调用 start() 方法时, 即启动了线程,线程就处于就绪状态,处于就绪状态的线程并不一定立即运行 run() 方法, 线程必须同其他线程竞争CPU 时间, 只有获得的才可以运行。
对于单CPU计算机系统,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态,因此可能有多个线程处于 就绪状态, 对于多个就绪状态的线程,是由java运行时系统的线程调度程序来调度的。
yield: 礼让线程,让当前正在执行的线程暂停,不是阻塞状态,而是让线程从运行状态进入就绪状态
让cpu重新调度(有可能继续调自己,也有可能礼让成功)
3、运行状态
当线程获得CPU时间后,才会进入运行状态,真正开始执行run()方法
4、阻塞状态 (sleep、join、wait、 其他操作io 进入阻塞状态)
是正在运行的线程在没有结束的情况下,让出CPU,也即让出了cpu timeslice,暂时停止运行。这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态
进入阻塞状态的几种情况:
1、等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
2、 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
3、 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。
当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5、 死亡状态 stop或destroy(已被弃) 推荐外部加一个标识 来控制是否执行
有两个原因会导致线程死亡:
1、 run方法正常退出而自然死亡;
2、 一个未捕获的异常终止了run方法而使线程猝死
确认是否存活 isAlive方法 可运行或者阻塞 返回true new且不是可运行的或者死亡 返回false
线程的集中状态值
NEW 新建状态
RUNNABLE 就绪状态、运行状态
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。
该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
BLOCKED 阻塞状态 (io流操作、wait)
WAITING、TIMED WAITING 阻塞状态(等待)(join、sleep)
TERMINATE 死亡状态
默认所有线程都是用户线程
BLOCKED
Java文档官方定义BLOCKED状态是:“这种状态是指一个阻塞线程在等待monitor锁。”
真实生活例子:今天你要去面试。这是你梦想的工作,你已经盯着它多年了。你早上起来,准备好,穿上你最好的外衣,对着镜子打理好。当你走进车库发现你的老婆已经把车开走了。在这个场景,你只有一辆车,所以怎么办?在真实生活中,可能会打架:-)。 现在因为你老爸把车开走了你被BLOCKED了。你不能去参加面试。
这就是BLOCKED状态。用技术术语讲,你是线程T1,你老婆是线程T2而锁是车。T1被BLOCKED在锁(例子里的车)上,因为T2已经获取了这个锁。
线程的 blocked状态往往是无法进入同步方法/代码块来完成的。这是因为无法获取到与同步方法/代码块相关联的锁。
WAITING
Java文档官方定义WAITING状态是:“一个线程在等待另一个线程执行一个动作时在这个状态”
真实生活例子:再看下几分钟后你的老婆开车回家了。现在你意识到快到面试时间了,而开车过去很远。所以你拼命地踩油门。限速120KM/H而你以160KM/H的速度在开。很不幸,一个交警发现你超速了,让你停到路边。现在你进入了WAITING状态。你听下车坐在那等着交警过来检查你并放行。基本上,只有等他让你走,你被卡在WAITING状态了。
用技术术语来讲,你是线程T1而交警是线程T2。你释放你的锁(例子中你停下了车),并进入WAITING状态,直到警察(例子中T2)让你走,你陷入了WAITING状态。
当线程调用以下方法时会进入WAITING状态:
Object#wait() 而且不加超时参数
Thread#join() 而且不加超时参数
LockSupport#park()
在对象上的线程调用了Object.wait()会进入WAITING状态,直到另一个线程在这个对象上调用了Object.notify()或Object.notifyAll()方法才能恢复。一个调用了Thread.join()的线程会进入WAITING状态直到一个特定的线程来结束。
与wating状态相关联的是等待队列,与blocked状态相关的是同步队列,一个线程由等待队列迁移到同步队列时,线程状态将会由wating转化为blocked。可以这样说,blocked状态是处于wating状态的线程重新焕发生命力的必由之路。
TIMED_WAITING
Java文档官方定义TIMED_WAITING状态为:“一个线程在一个特定的等待时间内等待另一个线程完成一个动作会在这个状态”
真实生活例子:尽管充满戏剧性,你在面试中做的非常好,惊艳了所有人并获得了高薪工作。(祝贺你!)你回家告诉你的邻居你的新工作并表达你激动的心情。你的朋友告诉你他也在同一个办公楼里工作。他建议你坐他的车去上班。你想这不错。所以第一天,你走到他的房子。在他的房子前停好你的车。你等了10分钟,但你的邻居没有出现。你继续开自己的车去上班,这样你不会在第一天就迟到。这就是TIMED_WAITING.
用技术术语来解释,你是线程T1而你的邻居是线程T2。你释放了锁(这里是停止开车)并等了足足10分钟。如果你的邻居T2没有来,你继续开车。
调用了以下方法的线程会进入TIMED_WAITING:
Thread#sleep()
Object#wait() 并加了超时参数
Thread#join() 并加了超时参数
LockSupport#parkNanos()
LockSupport#parkUntil()
网友评论