简述
本文主要介绍wait()、notify()、notifyAll()、join()、sleep()、yield()的含义与用法。
wait()
当线程调用一个共享变量(对象锁)的wait
方法时,该线程会被阻塞挂起,直到发送以下事件:
- 其他线程调用该共享变量(对象锁)notify()、notifyAll()方法
- 其他线程调用该线程的
interrupt
方法。
注:
- 如果调用 wait()方法的线程没有事先获取该对象的监视器锁 ,则调用 wait()方法时调用 线程会抛出 IllegalMonitorStateException 异常。
- 调用wait()方法后,线程会被挂起,同时只会释放该对象的监视器锁,如果当前线程还持有其他共享变量的锁,则这些锁是不会被释放的。
- 除非有另一个线程调用了notify()、notifyAll()、interrupt()方法,否则线程会一直阻塞
示例:
public class OtherTest {
public static Object lockA = new Object();
static class ThreadA extends Thread{
@Override
public void run() {
System.out.println("Thread A start");
synchronized (lockA) {
try {
lockA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread A end");
}
}
public static void main(String[] args) {
ThreadA t = new ThreadA();
t.start();
}
}
结果:
wait(long timeout)
在上述例子中可以看出,除非有另一个线程介入,否则调用wait的线程会一直阻塞。为了避免这种情况,可以在调用wait的时候传入一个timeout,在指定时间后停止阻塞。
notify()
唤起一个在调用了共享变量(对象锁)的wait系列方法之后阻塞的线程,如果有多个线程调用了同一个共享变量被阻塞,则调用notify方法时会随机唤醒一个。
notifyAll()
唤起全部调用了共享变量(对象锁)的wait系列方法之后阻塞的线程。
join()
在项目实践中经常会遇到一个场景,就是需要等待某几件事情完成后才能继续往下执行 , 比如多个线程加载资源 , 需要等待多个线程全部加载完毕再汇总处理。使用join
方法之后,会在线程运行完成之后在执行往下的操作。
如图所示,由于线程t没有执行完毕,则不会进行往下的执行。
sleep
当 一个执行中的线程调用了 Thread 的 sleep 方法后,调用线程会暂时让出指定时间的执行权,也就是在这期间不参与 CPU 的调度,但是该线程所拥有的监视器资源,比如锁还是持有不让出的 。 指定的睡眠时间到了后该函数会正常返回,线程就处于就绪状态,然后参与 CPU 的调度,获取到 CPU 资源后就可以继续运行了。
yield
当一个线程调用 yield 方法时,实际就是在暗示线程调度器当前线程请求让出自己 的 CPU 使用,但是线程调度器可以无条件忽略这个暗示。当一个线程调用 yield 方法时, 当前线程会让出 CPU 使用权,然后处于就绪状态,线程调度器会从线程就绪队列里面获取一个线程优先级最高的线程,当然也有可能会调度到刚刚让出 CPU 的那个线程来获取 CPU 执行权。
sleep与yield
总结 : sleep 与 yield 方法的区别在于,当线程调用 sleep 方法时调用线程会被阻塞挂起指定的时间,在这期间线程调度器不会去调度该线程 。 而调用 yield 方法时,线程只是让出自己剩余的时间片,并没有被阻塞挂起,而是处于就绪状态,线程调度器下一次调度时就有可能调度到当前线程执行 。
interrupt
中断线程。