# 线程状态

Java 的 Thread 类中对线程的状态有如下定义:

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

# NEW (新创建)

Thread state for a thread which has not yet started.

尚未启动的线程的线程状态。

此时线程刚刚创建,并未调用 start () 方法启动。

Thread thread = new Thread();
System.out.println(thread.getState()); // NEW

# RUNNABLE (可运行)

Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

可运行线程的线程状态。 处于可运行状态的线程正在 Java 虚拟机中执行,但它可能正在等待来自操作系统的其他资源,例如处理器。

线程调用 start () 方法开始运行,这个状态下也会发生一些等待,一般等待的是其他系统资源,而不是锁、sleep 等。

Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getState())); // RUNNABLE
thread.start();

# BLOCKED (被阻塞)

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}.

线程的线程状态被阻塞等待监视器锁定。 处于阻塞状态的线程正在等待监视器锁定以在调用 {@link Object#wait()Object.wait} 之后输入同步块 / 方法或重新输入同步块 / 方法。

这种状态是在有多个线程有同步操作的场景,如下 thread1 虽然释放了 CPU,但是没有释放 people 的锁,致使 thread2 进入了阻塞状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();
Thread thread2 = new Thread(() -> {
    synchronized (people) {
    }
});
thread2.start();

# WAITING (等待)

Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

{@link Object#wait() Object.wait} with no timeout

{@link #join() Thread.join} with no timeout

A thread in the waiting state is waiting for another thread to perform a particular action.

For example, a thread that has called <tt>Object.wait()</tt> on an object is waiting for another thread to call <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on that object. A thread that has called <tt>Thread.join()</tt> is waiting for a specified thread to terminate.

等待线程的线程状态。 由于调用以下方法之一,线程处于等待状态:

Object.wait()

Thread.join()

LockSupport.park()

处于等待状态的线程正在等待另一个线程执行特定操作。

例如,在对象上调用 Object.wait () 的线程正在等待另一个线程调用 Object.notify () 或 Object.notifyAll ()。 调用 Thread.join () 的线程正在等待指定的线程终止。

该状态下的线程处于等待状态,当另一线程唤醒这个线程时,线程立马进入就绪状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            people.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();

# TIMED_WAITING (计时等待)

Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:

{@link Object#wait(long) Object.wait} with timeout

{@link #join(long) Thread.join} with timeout

具有指定等待时间的等待线程的线程状态。 由于在指定的正等待时间内调用以下方法之一,线程处于定时等待状态:

Thread.sleep

Object.wait(long)

Thread.join(long)

LockSupport.parkNanos

LockSupport.parkUtil

该状态的线程需要等待一些时间才能继续运行。WAITING 状态是当发生某个事情才会进入就绪状态,TIMED_WAITING 状态是当时间到达就会进入就绪状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            people.wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();

# TERMINATED (被终止)

Thread state for a terminated thread. The thread has completed execution.

终止线程的线程状态。 线程已完成执行。

run () 方法执行结束后,线程进入 TERMINATED 状态。

# 主要方法

# wait()

wait () 方法是 Object 的方法,是在资源的角度阻塞线程,也就是让线程放弃对资源的占用。

public static void main(String[] args) {
    People people = new People();
    // 线程一拿到对象的锁
    Thread thread1 = new Thread(() -> {
       synchronized (people) {
           System.out.println(1);
           try {
               // 对象调用 wait 方法使线程进入 WAITING 状态
 			   //people 的锁被释放
               people.wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(2);
       }
    });
    thread1.start();
    // 线程二运行,拿到对象的锁
    Thread thread2 = new Thread(() -> {
       synchronized (people) {
           System.out.println(3);
       }
    });
    thread2.start();
}

运行结果:

1
3

因为线程一依旧处于阻塞状态,所以主线程 main 此时并没有结束运行。

# sleep()

sleep () 方法是线程的方法,是在线程的角度阻塞线程,无法操作对象锁,所以如果线程阻塞时锁住了某个对象,那么这个对象的锁将不会被释放。

public static void main(String[] args) {
    People people = new People();
    Thread thread1 = new Thread(() -> {
       synchronized (people) {
           System.out.println(1);
           try {
               // 线程调用 sleep 方法阻塞线程,线程进入 TIMED_WAITING
               // 对象的锁没有被释放
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(2);
       }
    });
    thread1.start();
    // 线程二拿不到 people 的锁所以不能执行进入就绪状态
    Thread thread2 = new Thread(() -> {
       synchronized (people) {
           System.out.println(3);
       }
    });
    thread2.start();
}

运行结果:

1
2
3

两者的区别:

sleep()wait()
所属类不同Thread 类的方法Object 类的方法
时间不同必须指定时间可指定也可不指定时间
释放锁不同释放 CPU 执行权不释放锁释放 CPU 执行权释放锁
使用范围不同可以在任意地方使用只能在同步代码中使用

# notify()

参考 Java 源码 --Object

notify () 和 notifyAll () 方法唤醒被 wait () 方法置于 WAITING 状态的线程。notify () 方法唤醒一个等待资源的线程,如果有多个线程同时等待一个资源,则由 JVM 选择一个线程唤醒,使其进入就绪状态,重新竞争锁。

public static void main(String[] args) {
    People people = new People();
    Thread thread1 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(1);
                //thread1 进入 WAITING 状态
                // 释放锁
                people.wait();
                System.out.println(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread1.start();
    Thread thread2 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(3);
                people.wait();
                System.out.println(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread2.start();
    Thread thread3 = new Thread(() -> {
        synchronized (people) {
            System.out.println(5);
            // 唤醒一个等待 people 锁的线程
            people.notify();
            System.out.println(6);
        }
    });
    thread3.start();
}

运行结果如下,thread2 被唤醒,thread1 依旧处于 WAITING 状态。

1
3
5
6
4

# notifyAll()

notifyAll () 方法唤醒所有等待资源的线程。

public static void main(String[] args) {
    People people = new People();
    Thread thread1 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(1);
                people.wait();
                System.out.println(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread1.start();
    Thread thread2 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(3);
                people.wait();
                System.out.println(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread2.start();
    Thread thread3 = new Thread(() -> {
        synchronized (people) {
            System.out.println(5);
            // 唤醒所有等待 people 锁的线程
            people.notifyAll();
            System.out.println(6);
        }
    });
    thread3.start();
}

运行结果如下,thread1 和 thread2 均被唤醒。

1
3
5
6
4
2

# yield()

yield () 方法把 CPU 让给同等优先级或更高优先级的线程。注意,其他线程不会立马进入运行状态,只是给其他线程提供竞争的机会。

public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
        System.out.println(1);
        Thread.yield();
        System.out.println(2);
    });
    thread1.setPriority(Thread.MIN_PRIORITY);
    thread1.start();
    Thread thread2 = new Thread(() -> System.out.println(3));
    thread2.setPriority(Thread.MAX_PRIORITY);
    thread2.start();
}

运行结果:

1
2
3

1
3
2

thread1 礼让之后,thread1 和 thread2 一起参与竞争,都有可能进入运行状态。疑惑?此处 thread2 的优先级已被设为最高了,为什么不一定是 thread2 先运行呢?

# join()

join () 方法会使当前线程等待调用 join () 方法的线程结束后才能继续执行。

public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
        try {
            Thread.sleep(10000);
            System.out.println("我刚睡醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    thread1.start();
    Thread thread2 = new Thread(() -> {
        try {
            System.out.println(1);
            thread1.join();
            System.out.println(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    thread2.start();
}

运行结果:

1
我刚睡醒
2