Thread -- 07 -- notify()和notifyAll()的区别

原文链接:Thread – 07 – notify()和notifyAll()的区别


相关文章:


这里我们再来了解下 notify() 方法和 notifyAll() 方法的区别


一、举例说明

public class NotificationDemo {
    private volatile boolean go = false;

    public static void main(String[] args) throws InterruptedException {
        final NotificationDemo test = new NotificationDemo();
        Runnable waitTask = () -> {
            try {
                test.shouldGo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " finished Execution");
        };

        Runnable notifyTask = () -> {
            test.go();
            System.out.println(Thread.currentThread().getName() + " finished Execution");
        };

        Thread t1 = new Thread(waitTask, "WT1");
        Thread t2 = new Thread(waitTask, "WT2");
        Thread t3 = new Thread(waitTask, "WT3");
        Thread t4 = new Thread(notifyTask,"NT1");

        // starting all waiting thread
        t1.start();
        t2.start();
        t3.start();

        // pause to ensure all waiting thread started successfully
        Thread.sleep(200);

        // starting notifying thread
        t4.start();

    }
    
    /*
     * wait and notify can only be called from synchronized method or bock
     */
    private synchronized void shouldGo() throws InterruptedException {
        while(!go){
            System.out.println(Thread.currentThread().getName() + " is going to wait on this object");
            wait(); // release lock and reacquires on wakeup
            System.out.println(Thread.currentThread().getName() + " is woken up");
        }
        go = false; // resetting condition
    }

    /*
     * both shouldGo() and go() are locked on current object referenced by "this" keyword
     */
    private synchronized void go() {
        while (!go){
            System.out.println(Thread.currentThread().getName() + " is going to notify all or one thread waiting on this object");
            go = true; //making condition true for waiting thread
            notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke up
            // notifyAll(); // all waiting thread  WT1, WT2,WT3 will woke up
        }

    }
}
  • 如上所示,我们首先定义了一个状态标识 go,其由 volatile 关键字进行修饰 (当有多个线程会对该变量进行操作时,一旦有一个线程对其进行了改动,其他线程就能立即看到该变量的改动)

  • 然后定义了两个方法 shouldGo() 和 go()

    • shouldGo()

      • 当 go 为 false 时,进入循环执行代码,然后调用 wait() 方法进入休眠状态,同时释放 test 对象锁;当执行完循环逻辑后,重新将 go 置为 false
    • go()

      • 当 go 为 false 时,进入循环执行代码,然后将 go 置为 true,接着去随机唤醒等待池中的一个线程或唤醒等待池中的所有线程

  • 调用 notify() 的输出结果

    WT1 is going to wait on this object
    WT2 is going to wait on this object
    WT3 is going to wait on this object
    NT1 is going to notify all or one thread waiting on this object
    NT1 finished Execution
    WT1 is woken up
    WT1 finished Execution
    
    • 由输出结果可知,线程 WT1 先获取到了 test 对象锁,执行 shouldGo() 方法,接着调用 wait() 方法释放了 test 对象锁,进入阻塞状态

    • 此后,线程 WT2、WT3 重复线程 WT1 的流程,纷纷进入阻塞状态

    • 此时,主线程在休眠了 200 ms 后,线程 NT1 开始执行,获取到 test 对象锁,并执行 go() 方法,将 变量 go 设置为 true,然后随机唤醒了等待池中的一个线程 (这里唤醒了 WT1)

    • 唤醒线程 WT1 后,此时 test 对象锁仍由线程 NT1 持有,因此此时线程 WT1 位于锁池当中,等待 test 对象锁被释放

    • 线程 NT1 执行完毕后,释放了 test 对象锁,由线程 WT1 获取到,此时线程 WT1 继续执行,执行完一遍循环后,由于此时变量 go 为 true,则结束了循环,并将变量 go 重新设置为了 false

    • 线程 WT1 执行完毕,而线程 WT2、WT3 仍处于等待池中,但此时已经没有线程可以将它们唤醒了


  • 调用 notifyAll() 的输出结果

    WT1 is going to wait on this object
    WT2 is going to wait on this object
    WT3 is going to wait on this object
    NT1 is going to notify all or one thread waiting on this object
    NT1 finished Execution
    WT2 is woken up
    WT2 finished Execution
    WT3 is woken up
    WT3 is going to wait on this object
    WT1 is woken up
    WT1 is going to wait on this object
    
    • 同上,不同的是 NT1 唤醒了等待池中的所有线程,三个线程从等待池中被唤醒后进入锁池去争夺 test 对象锁,并将变量 go 设置为 true

    • 这里由线程 WT2 获取到了 test 对象锁,线程 WT2 执行完毕后,又将变量 go 重新设置为 false

    • 因此线程 WT3、WT1 会继续进行循环逻辑,并再次调用 wait() 方法进入阻塞状态,而此时已经没有线程可以将它们唤醒了


二、归纳总结

  • 调用方法后,唤起休眠线程的数量不同

    • 调用 notify() 方法只会随机选取一个处于等待池中的线程进入锁池中去竞争获取锁的机会

    • 调用 notifyAll() 方法会让所有处于等待池中的线程进入锁池中去竞争获取锁的机会

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值