# 简述
操作系统中的线程和编程语言中的线程是一一对应的, 在这篇文章中, 我要让自己彻底弄懂线程.
# 操作系统的线程生命周期
要想弄懂线程, 首先得清楚它是一个什么概念, 可以去Wikipedia上了解, 其次你需要线程的生命周期, 对它有个宏观上的了解.
每种编程语言对操作系统的线程都进行了不同程度的封装(可能是组合, 也可能是细分), 所以我们有必要来先了解下操作系统的线程生命周期.
下图为操作系统的生命周期:
# 状态是如何转换的
# 1. NEW
此状态一般被称为"新建", 属于编程语言层面的状态, 不是由操作系统实现.
在Java中继承Thread或实现Runnable就可以创建一个
NEW状态线程, 注意此时没有调用start()哦.
# 2. NEW -> RUNNABLE
线程在操作系统中被创建, 等待CPU的调度.
在Java中对创建后的线程调用start(), 其状态即由NEW变为RUNNABLE, 等待时间片的分配.
# 3. RUNNABLE -> RUNNING
CPU分配了时间片给线程, 则线程状态变为
RUNNINGJava中统一为
RUNNABLE
# 4. RUNNING -> SLEEP
当运行中的线程
调用某个阻塞API或等待某个事件时, 线程状态变为SLEEP(休眠状态), 释放CPU时间片, SLEEP状态的线程永远没有机会获得CPU时间片. 当等待事件结束或者阻塞API调用结束, 线程由SLEEP状态再变为RUNNABLE.
# 5. RUNNING -> TERMINATED
线程执行完或者发生异常就会变成TERMINATED状态, 此状态的线程不会再有状态变更了, 同时也表示线程的生命周期结束了.
# Java线程的生命周期
上面说完操作系统的生命周期, 下面来聊聊正题, 那Java线程的生命周期是什么样的?
下图为Java线程的生命周期:
# 状态之间如何转换
# 1. NEW
Java有两种创建线程的方式
- 继承Thread类
- 实现Runnable接口
创建线程之后, 此线程就处于NEW状态, 这是属于
编程语言层面的状态
# 2. NEW -> RUNNABLE
对创建的线程类调用start(), 即将线程状态由NEW变为RUNNABLE
# 3. RUNNABLE -> BLOCKED
线程等待synchronized的隐式锁时, 等待线程会从RUNNABLE变为BLOCKED
# 4. RUNNABLE -> WAITING
三种场景会触发此状态变换:
- 调用Object.wait();
- 调用Thread.join();
- 调用LockSupport.park();
# 5. RUNNABLE ->TIMED_WAITING
五种场景会触发此状态变换:
- 调用Thread.sleep(long l);
- 调用Object.wait(long l);
- 调用Thread.join(long l);
- 调用LockSupport.parkNanos(Object blocker, long l);
- 调用LockSupport.parkUntil(long l);
# 6. RUNNABLE -> TERMINATED
两种常见场景:
- 线程执行完
- 发生异常
使用stop()已经不推荐了, 正确停止线程请使用interrupt()
# Java为什么没有RUNNING状态
Java将RUNNABLE和RUNNING统一归为
RUNNABLE状态
# 阻塞式API或等I/O时为什么不是BLOCKED状态
进行这两类操作时,
操作系统会将线程由RUNNING变为SLEEP, 但是在JVM中都统一归为RUNNABLE状态.