并发和多线程(三)--线程的生命周期/状态
线程的生命周期或者说状态其实不复杂,但是很多人的理解可能有错误,一个典型的误区,线程运行时的状态是Runnable,而不是Running,因为线程没有Running状态。
线程的状态
1、New:已创建,没启动。还没有执行start()
2、Runnable:调用start()之后就处于Runnable,无论是否已经运行,都是Runnable状态,对应操作系统的Ready和Running状态。
3、Blocked:进入Synchronized修饰的方法或者代码块,但是无法获取锁,就处于Blocked。
4、Waiting:线程进入等待的阻塞状态,例如调用Object.wait()。
5、Timed-Waiting:线程进入计时等待的阻塞状态,例如调用Thread.sleep(time)。
6、Terminated:线程执行代码结束,或者出现未捕捉的异常。
PS:线程没有Running状态,请参考官方文档:https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.State.html
线程的状态转换
从上图,可以明确看到状态如何进行转换,状态之间的变化是否可逆。。。
其实,从Waiting到Blocked状态可以可以的,当Waiting状态被唤醒之后,如果暂时没有获取到monitor锁,这时候就会进入Blocked状态,当获取锁之后,重新变成Runnable。Waiting和Timed-Waiting状态下在出现未捕获异常时,就会直接进入Terminated。
PS:Waiting和Timed-Waiting状态下通过interrupt()响应中断,会进入Runnable状态。
验证线程状态
为了上面所讲线程状态的可信度,我们通过代码进行验证
1、New、Runnable、Terminated
public static void main(String[] args) throws InterruptedException{ Thread thread = new Thread(() -> { for (int i = 0; i <= 4; i++) { log.info("{}", i); if (i == 2) { log.info("子线程运行过程中状态:{}", Thread.currentThread().getState()); } } }); log.info("子线程没有执行start时,状态:{}", thread.getState()); thread.start(); log.info("子线程执行start后,状态:{}", thread.getState()); Thread.sleep(10); log.info("子线程执行结束,状态:{}", thread.getState()); }
结果: 17:12:11.244 [main] INFO com.diamondshine.Thread.ThreadClass - 子线程没有执行start时,状态:NEW 17:12:11.251 [main] INFO com.diamondshine.Thread.ThreadClass - 子线程执行start后,状态:RUNNABLE 17:12:11.251 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 0 17:12:11.251 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 1 17:12:11.251 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 2 17:12:11.252 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 子线程运行过程中状态:RUNNABLE 17:12:11.252 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 3 17:12:11.252 [Thread-0] INFO com.diamondshine.Thread.ThreadClass - 4 17:12:11.262 [main] INFO com.diamondshine.Thread.ThreadClass - 子线程执行结束,状态:TERMINATED
成功验证了在子线程执行过程中的状态是Runnable,而不是Running。
2、Blocked、Waiting、Time-Waiting
@Slf4j public class ThreadClass implements Runnable{ public static void main(String[] args) throws InterruptedException{ ThreadClass threadClass = new ThreadClass(); Thread thread = new Thread(threadClass); thread.start(); Thread thread1 = new Thread(threadClass); thread1.start(); //sleep 5ms为了让子线程执行到synchronize()的Thread.sleep(1000) try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } log.info("第一个线程的状态:{}", thread.getState()); //此时第一个线程获取monitor锁,然后休眠1000ms,所以第二个线程无法获得锁 log.info("第二个线程的状态:{}", thread1.getState()); //休眠1100ms为了让代码执行到wait(); Thread.sleep(1100); log.info("第一个线程的状态:{}", thread.getState()); } @Override public void run() { synchronize(); } private synchronized void synchronize() { try { Thread.sleep(1000); wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } }
结果: 17:46:19.601 [main] INFO com.diamondshine.Thread.ThreadClass - 第一个线程的状态:TIMED_WAITING 17:46:19.608 [main] INFO com.diamondshine.Thread.ThreadClass - 第二个线程的状态:BLOCKED 17:46:20.708 [main] INFO com.diamondshine.Thread.ThreadClass - 第一个线程的状态:WAITING
验证结果符合预期,当调用sleep(),线程处于Timed_Waiting,因为Synchronized进入阻塞,处于Blocked,调用wait(),处于waiting状态。