wait、sleep、yield、join的区别

发布时间 2023-09-16 20:13:40作者: 乐子不痞

两个概念

1、锁队列

所有需要竞争同步锁的线程都会放在锁队列中,比如当前对象的锁已经被一个线程得到,则其他线程都需要在这个锁队列中进行等待,当前面的线程释放同步锁后,锁队列中的线程去竞争同步锁,当某个线程得到后会进入就绪队列进行等待CPU资源分配。

2、等待队列(wait方法)

在调用wait() 方法后,线程会放到等待队列中,等待队列的线程是不会去竞争同步锁的。只有调用了 notify() 或 notifyAll() 后等待队列的线程才会开始去竞争锁,notify() 是随机从等待队列中选出一个线程放到锁队列中,而notifyAll() 是将等待队列中的所有线程都放到锁队列中。

wait 和 sleep 的区别

  1. sleep 是 Thread 类的静态本地方法,wait 是 Object 类的本地方法。

  2. sleep 不会释放锁资源,但wait 会释放锁资源,而且会加入到锁等待队列中。

    sleep 就是把 CPU 的执行资格和执行权释放出去,不会再执行此线程,当定时时间结束后再取回CPU资源,参与CPU的调度,获取CPU资源后就可以继续运行、而如果 sleep 的时候该线程有锁,那么 sleep 不会释放这个锁,而是把锁带着一起进入睡眠状态,也就是说其他需要这个锁的线程根本不可能获得这个锁。如果在睡眠期间其他线程调用了这个线程 interrupt 方法,那么这个线程也会抛出 interruptException 异常返回,这点和 wait 是一样的。

  3. sleep 方法不依赖于同步器 synchronized ,但是 wait 方法需要依赖 synchronized 关键字一起才能执行。

  4. sleep 不需要被唤醒(休眠之后退出阻塞),但是 wait 需要被 notify() 或 notifyAll() 唤醒。

  5. sleep 一般用于当前线程休眠,或者轮休暂停操作,而 wait 多用于多线程直接的通信。

  6. 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();
            }
        }
    }
}