Object类
wait
- wait():无期限的等待,直到被notify()或notifyAll()方法唤醒,或被interrupt()方法打断;
- wait(long timeout):效果同wait(),区别在于最多等待指定毫秒值的时间;
- wait(long timeout, int nanos):同上,多一个参数是指纳秒值,但实际上该纳秒值并不准确,无论输入多少,相当于毫秒值加一;
wait方法的使用
wait方法的使用必须获取Monitor的Owner才能被调用(也就是获取到当前对象的锁),否则会抛IllegalMonitorStateException,如下图代码和返回。
当放开注释,程序获取到锁之后,再调用方法,可以看到,线程一直处于等待状态,线程一直没有结束。当调用完wait()方法后,会释放锁。
notify
随机唤醒某一处于等待状态的线程,类似wait方法,同样需要先获取对象锁才能调用
notifyAll
唤醒所有处于等待状态的线程,类似wait方法,同样需要先获取对象锁才能调用
@Slf4j
public class Test01 {
private static Object obj = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (obj) {
log.info("t1 running");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("t1 waked up");
}
}, "t1");
Thread t2 = new Thread(() -> {
synchronized (obj) {
log.info("t2 running");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("t2 waked up");
}
}, "t2");
Thread t3 = new Thread(() -> {
synchronized (obj) {
log.info("t3 running");
// obj.notify();
obj.notifyAll();
}
}, "t3");
t1.start();
t2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t3.start();
}
}
调用notify()方法的返回结果,随机唤醒t1或t2线程
调用notifyAll()方法的返回结果,t1、t2线程都被唤醒
Thread类
join
使当前线程等待指定线程运行结束后才执行,底层是使用的wait()方法
注意:本质上是让当前线程调用wait()方法,而不是让指定的thread对象调用wait()方法,当指定线程运行结束,虚拟机底层会调用notifyAll方法唤醒其他等待该线程的线程,所以最后产生的结果是当前线程等待指定线程运行结束后才继续执行。
sleep
使线程休眠指定毫秒值,直到时间结束或被interrupt()方法打断
可以看到,日志间隔了2秒才打印。
yield
使当前线程让出cpu时间片,重新进入cpu时间片的竞争。和sleep的区别在于,sleep会休眠指定时间,这段时间是不会分配到cpu时间片的,而yield方法可能出现刚让出时间片,又立马竞争到时间片的情况。
interrupt
打断指定线程,使其由Timed Waiting状态变成Runnable状态
当被打断,会进入catch代码块。