

java.lang.Thread类内部维护了一个枚举类State,包含了Java线程的6种状态
public enum State {
//新建
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}

其中的RUNNABLE包括了运行状态与就绪状态
new Thread()创建了一个线程,还没有执行start()方法。此时线程状态是NEW
调用的start(),这个线程会执行它的run()方法,此时进入RUNNABLW状态
在进入synchronized代码块/方法 时,如果线程没有获取到对应的monitor锁,就会从Runnable运行状态进入Blocked阻塞状态
只有通过synchronized会进入阻塞Blocked。
对于其他锁(ReentrantLock等),如果线程没有获取到锁,会直接进入Waiting状态
本质就是执行了LockSupport.park()方法进入Waiting状态
wait()/join()也会进入等待
BLOCKED阻塞状态 与 WAITING等待状态的区别
线程会进入超时等待的条件:执行以下带时间参数的方法时
| 方法 | 方法签名 | 所属类 |
|---|---|---|
wait(long timeout) | public final native void wait(long timeout) | Object |
sleep(long millis) | public static native void sleep(long millis) | Thread |
join(long millis) | public final synchronized void join(long millis) | Thread |
parkNanos(Object blocker, long nanos) | public static void parkNanos(Object blocker, long nanos) | LockSupport |
parkUntil(Object blocker, long deadline) | public static void parkUntil(Object blocker, long deadline) | LockSupport |
LockSupport的park和unpark方法都是调用Unsafe类的本地方法

Runnable进入Blocked是因为没有获得锁才进入了阻塞;
所以被阻塞的线程获得其他线程释放的monitor锁后,才可以从Blocked到Runnable
如果通过其他线程调用notify()或 notifyAll()来唤醒它,那么它会直接进入Blocked 状态这里需要注意一点,因为唤醒 waiting线程的线程如果调用notify/notifyAll,要求必须先持有该 monitor锁,也就是wait、notify、notifyAll 必须在synchronized 代码块中。

所以处于 waiting 状态的线程被唤醒时拿不到该锁,就会进入 Blocked 状态,直到执行了notify/notifyAll 唤醒它的线程执行完并且释放了 monitor锁,才可能轮到它去尝试获取这把锁,如果它得到了锁,就会从Blocked 状态进入Runnable状态。