在 Java 领域, 实现并发程序的主要手段就是多线程. 线程是操作系统里的一个概念, Java 语言里的线程本质上就是操作系统的线程, 它们是一一对的. 通用的线程生命周期(在操作系统调度层面)
Java 线程 (JVM 层面) 的生命周期可以简化为下图:
Java 语言里细化了休眠状态, 把可运行状态和运行状态合并了
1.RUNNABLE 与 BLOCKED 的状态转换
线程等待 synchronized 的隐式锁, 等待的线程就会从 RUNNABLE 转换到 BLOCKED 状态. 而当等待的线程获得 synchronized 隐式锁时, 就又会从 BLOCKED 转换到 RUNNABLE 状态.
线程调用阻塞式 API 时, 在操作系统层面, 线程是会转换到休眠状态的, 但是在 JVM 层面, Java 线程的状态不会发生变化, 也就是说 Java 线程的状态会依然保持 RUNNABLE 状态. 因为在 JVM 看来, 等待 CPU 使用权 (操作系统层面此时处于可执行状态) 与等待 I/O(操作系统层面此时处于休眠状态)没有区别, 都是在等待某个资源, 所以都归入了 RUNNABLE 状态.
RUNNABLE 与 WAITING 的状态转换
获得 synchronized 隐式锁的线程, 调用无参数的 Object.wait() 方法.
一个线程对象 thread A, 当调用 A.join() 的时候, 执行这条语句的线程会等待 thread A 执行完, 而等待中的这个线程, 其状态会从 RUNNABLE 转换到 WAITING. 当线程 thread A 执行完, 原来等待它的线程又会从 WAITING 状态转换到 RUNNABLE.
调用 LockSupport.park() 方法, 当前线程会阻塞, 线程的状态会从 RUNNABLE 转换到 WAITING. 调用 LockSupport.unpark(Threadthread) 可唤醒目标线程, 目标线程的状态又会从 WAITING 状态转换到 RUNNABLE.
RUNNABLE 与 TIMED_WAITING 的状态转换
从 NEW 到 RUNNABLE 状态
调用线程对象的 start() 方法
从 RUNNABLE 到 TERMINATED 状态
线程执行完 run() 方法后, 会自动转换到 TERMINATED 状态, 当然如果执行 run() 方法的时候异常抛出, 也会导致线程终止. 强制中断 run() 方法的执行, 用 Thread 类里面 stop() 和 interrupt() 方法.
stop() 和 interrupt() 方法的主要区别
stop() 方法会真的杀死线程, 如果线程持有 ReentrantLock 锁, 被 stop() 的线程会自动调用 ReentrantLock 的 unlock() 去释放锁. 已经标记为 @Deprecated, 所以不建议使用了.
interrupt() 方法仅仅是通知线程, 线程有机会执行一些后续操作, 同时也可以无视这个通知. 被中断的线程通过异常和主动检测的方式获得了通知
当线程 A 处于 WAITING,TIMED_WAITING 状态时, 或者当线程 A 处于 RUNNABLE 状态时, 并且阻塞在 java.nio.channels.InterruptibleChannel /java.nio.channels.Selector 上时, 如果其他线程调用线程 A 的 interrupt() 方法, 线程 A 会触发 InterruptedException/java.nio.channels.ClosedByInterruptException / 直接返回. 抛出异常后, 中断标示会自动清除掉.
如果线程处于 RUNNABLE 状态, 并且没有阻塞在某个 I/O 操作上, 其他线程调用线程 A 的 interrupt() 方法, 那么线程 A 可以通过 isInterrupted() 方法, 检测是不是自己被中断了.
来源: http://www.bubuko.com/infodetail-3653628.html