了解线程的状态,是学习多线程的基石。
前文说过,线程的存在,就是希望程序能够更有效的利用CPU的资源,但我们都知道,CPU的资源只有一份,调度好线程对资源的合理利用和占用是很困难的。使用线程的时候,我们应该确保线程之间的耦合,确保一个线程不应该干扰另一个线程的执行,确保同步锁的获得与释放都是井然有序的。比如一个线程获取了一个同步锁而正在运行时,那么另外想要获取该同步锁的线程就要进行阻塞等待。这里就涉及到了两个线程的状态:运行中与阻塞。那么,线程都有哪些状态呢?废话不再多说,直接上图。
创建线程的目的就是为了运行,如果不考虑其他,那么主要就两个状态:Run(线程运行) Dead(运行结束,线程死亡)。但是要能保证线程与线程之间正确的调度,那么就要有其他的几个状态,比如想上面讲到的,一个线程获得了同步锁,别的线程等不到同一把锁,获得不了CPU的占有权,但它又不想去死,只能去其他的状态去阻塞等待,就是Blocked状态。
这里将线程的状态主要分为5种:
1. new 新建状态:一个线程被新建之后就进入了新建状态,比如简单的创建线程的方式:Thread t1 = new Thread();
2. Runnable 就绪状态: 处于就绪状态,随时可能被CPU调度执行,但注意进入就绪状态并不是马上就会运行。当一个线程执行t1.start()方法时,就进入了就绪状态,当然也可能从其他状态转换到该状态。
3. Running 运行状态:线程获取CPU资源进行运行。注意只有从就绪状态才能进去运行状态。
4. Dead 死亡状态:线程执行结束或者因异常退出运行,线程生命周期至此结束。
5. Blocked 阻塞状态:阻塞状态具体分为三种:
(1) 等待阻塞 – 通过调用wait()方法,让线程进入等待阻塞状态,等待其他任务的完成。
(2) 同步阻塞 – 当线程A在执行一段被synchronized关键字修饰的方法或者代码块的时候,因为其他线程B已经获得了对应的同步锁时,线程A会进入同步阻塞状态。
(3) 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新进入就绪状态。
总结:就像这篇的题目开头,了解线程的状态,以及各种状态之间的转化,是学习多线程的基石。