对Java线程状态的思考
Java中的线程状态
具体可参见
java.lang.Thread.State枚举类。
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
- 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。

Java线程的三种暂停状态:
- WAITING
- TIMED_WAITING
- BLOCKED
几种暂停方法的比较:
Thread.sleep(long millis),当前执行线程调用此方法。出让CPU,但不释放锁资源。进入TIMED_WAITING,结束进入就绪状态Thread.yield(),当前执行线程调用此方法。出让CPU,但不释放锁资源。Thread.join()/Thread.join(long millis),当前执行线程调用其他线程的join方法,不释放锁资源。Object.wait(),当前线程调用对象的wait方法,当前线程释放锁资源,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒。Object.notify(),唤醒在此对象监视器(monitor)上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器(monitor)上等待的所有线程。LockSupport.park()/LockSupport.parkNanos(long nanos)/LockSupport.parkUntil(long deadlines), 当前线程进入WAITING/TIMED_WAITING状态。对比wait方法,不需要获得锁就可以让线程进入WAITING/TIMED_WAITING状态,需要通过LockSupport.unpark(Thread thread)唤醒。
操作系统的进程状态
- New(创建)- 进程处于正在被创建的过程中。
- Ready(就绪)- 进程运行所需资源已经就绪,但是CPU还未运行该进程的指令。
- Running(运行)- CPU正在运行该进程的指令。
- Waiting(等待) - 进程此时无法运行,因为在等待某些资源就绪或等待某些事件发生。如等待键盘输入,磁盘访问请求,进程间通信消息,时间片轮转结束或者一个子进程执行结束。
- Terminated(终止) - 该进程执行完毕。
简易模式:

详细模型:

操作系统进程大致可分为两种实现方式:
- 由程序员自主创建、销毁、调度的用户态下的线程
- 直接由内核所管理、创建的内核线程。
用户线程:优势在于线程的切换不需要从用户态切换到内核态,但如果进程中的某一线程由于IO请求,导致线程阻塞,操作系统会直接阻塞整个进程。
内核线程:由内核(Kernel)进行创建调度,内核通过操作调度器(Scheduler)对线程进行调度。内核线程与用户态下的线程是一对一的关系。执行多线程的内核叫做多线程内核(Multi-Threads Kernel)。也就是我们现在常常对一个处理器的描述:如8核心16线程。
这里插一句题外话,多核心数也有可能带来相应的问题,同一进程的不同线程如果在不同的内核上,就会有内存共享的开销。
PS:讲的比较简单,感兴趣的朋友可以详细看一看《现代操作系统》中对进程、线程相关的描述。
Java线程在操作系统上的体现
Java虚拟机封装了对实际线程的处理。JDK1.2之前使用的自定义的用户线程,1.2及其之后使用的是基于操作系统的内核态线程模型。
封装后概念的差异性:
- 操作系统中的
waiting对应了Java线程中的三种状态(等待(waiting)、超时等待(time_waiting)、阻塞(blocked)) - Java线程的
Runnable状态整合了操作系统线程的Ready与Running的状态。

浙公网安备 33010602011771号