线程状态
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
{@link LockSupport#park() LockSupport.park}
A thread in the waiting state is waiting for another thread to perform a particular action.
For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() 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 #sleep Thread.sleep}
{@link Object#wait(long) Object.wait} with timeout
{@link #join(long) Thread.join} with timeout
{@link LockSupport#parkNanos LockSupport.parkNanos}
{@link LockSupport#parkUntil LockSupport.parkUntil}
具有指定等待时间的等待线程的线程状态。 由于在指定的正等待时间内调用以下方法之一,线程处于定时等待状态:
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()
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