wait、sleep、yield、join的区别
两个概念
1、锁队列
所有需要竞争同步锁的线程都会放在锁队列中,比如当前对象的锁已经被一个线程得到,则其他线程都需要在这个锁队列中进行等待,当前面的线程释放同步锁后,锁队列中的线程去竞争同步锁,当某个线程得到后会进入就绪队列进行等待CPU资源分配。
2、等待队列(wait方法)
在调用wait() 方法后,线程会放到等待队列中,等待队列的线程是不会去竞争同步锁的。只有调用了 notify() 或 notifyAll() 后等待队列的线程才会开始去竞争锁,notify() 是随机从等待队列中选出一个线程放到锁队列中,而notifyAll() 是将等待队列中的所有线程都放到锁队列中。
wait 和 sleep 的区别
-
sleep 是 Thread 类的静态本地方法,wait 是 Object 类的本地方法。
-
sleep 不会释放锁资源,但wait 会释放锁资源,而且会加入到锁等待队列中。
sleep 就是把 CPU 的执行资格和执行权释放出去,不会再执行此线程,当定时时间结束后再取回CPU资源,参与CPU的调度,获取CPU资源后就可以继续运行、而如果 sleep 的时候该线程有锁,那么 sleep 不会释放这个锁,而是把锁带着一起进入睡眠状态,也就是说其他需要这个锁的线程根本不可能获得这个锁。如果在睡眠期间其他线程调用了这个线程 interrupt 方法,那么这个线程也会抛出 interruptException 异常返回,这点和 wait 是一样的。
-
sleep 方法不依赖于同步器 synchronized ,但是 wait 方法需要依赖 synchronized 关键字一起才能执行。
-
sleep 不需要被唤醒(休眠之后退出阻塞),但是 wait 需要被 notify() 或 notifyAll() 唤醒。
-
sleep 一般用于当前线程休眠,或者轮休暂停操作,而 wait 多用于多线程直接的通信。
-
sleep 会让出CPU执行时间且强制上下文切换,而 wait 则不一定,wait 后可能还是有机会重新竞争到锁继续执行。
yield
yield() 执行后线程直接进入就绪状态,马上释放了CPU的执行权,但是依然保留了CPU的执行资格,有可能在CPU下次进行线程调度时还让这个线程获取到执行权继续执行。
join
join() 执行后线程进入阻塞状态,例如在线程B中调用线程A的 join() 方法,那么线程B会进入到阻塞队列,直到线程A结束或者中断线程。
public class ThreadJoin extends Thread {
private int i = 1;
@Override
public void run() {
for (; i < 10; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 5) {
ThreadJoin t1 = new ThreadJoin();
t1.start();
//main 线程调用了t1 线程的join() 方法,所以必须等t1 执行结束才会向下执行
t1.join();
}
}
}
}