Java 并发编程主要是通过多线程实现的,而线程的操作系统中的概念。Java 中的线程其本质上就是操作系统中的线程,但是 Java 语言对操作系统的线程做了封装。
Java 线程的生命周期,即 了解线程各个节点状态的转换机制 。了解 Java 线程生命周期有助于跟踪分析线程的状态,通过分析线程 dump 来解决死锁、饥饿、活锁的问题。
前面介绍了通用的线程生命周期模型——五态模型,编程语言会对操作系统对线程的操作进行封装,所以 Java 的生命周期模型和通用的线程生命周期模型有所不同,它有初识状态、运行/可运行状态、休眠状态和终止状态,其中休眠状态细分为 BLOCKED、WATING、TIMED_WATING,共 6 中状态,如下图所示:
NEW 状态是在编程语言层面创建线程,而操作系统层面还没有创建线程。Java 创建线程有 3 种方式:
从 NEW 状态到 RUNNABLE 状态,就是在操作系统层面创建线程,此时需要调用 Thread.start()
方法:
MyThread myThread = new MyThread(); // 从 NEW 状态转换到 RUNNABLE 状态 myThread.start();
只有一种场景会触发这种转换,即线程等待 synchronized 隐式锁,此时只有一个线程能执行被 synchronized 修饰的方法或代码块,其他线程就进入 BLOCKED 状态。
当等待的线程获得 synchronized 隐式锁时,就会从 BLOCKED 状态转换为 RUNNABLE 状态。
有三种场景会触发这种转换。
第一种,获取到 synchronized 隐式锁的线程调用 Object.wait()
方法,线程会从 RUNNABLE 状态转变为 WATING 状态。调用 Object.notify()
或者 Object.notifyAll()
会从 WATING 状态变为 RUNNABLE 状态。
第二种,线程调用 Thread.join()
, join()
是这一种线程同步的方法,当主线程调用 Thread A 的 A.join() 方法时,主线程就会从 RUNNABLE 转换为 WATING,当线程 A 执行完之后,又从 WATING 转换为 RUNNABLE。
第三种,调用 LockSupport.park()
当前线程会阻塞,线程的状态会从 RUNNABLE 转换到 WAITING。调用 LockSupport.unpark(Thread thread)
可唤醒目标线程,目标线程的状态又会从 WAITING 状态转换到 RUNNABLE。
Thread.sleep(long millis) Object.wait(long timeout) Thread.join(long millis) LockSupport.parkNanos(Object blocker, long deadline) LockSupport.parkUntil(long deadline)
run() run() Thread.stop() Thread.interrupt()