notifyAll唤醒线程的范围?

执键写春秋
• 阅读 1615

今天看到开源中国上有这样一个问答:假设我有两个对象锁,对象A锁有5个线程在等待,对象B锁有3个线程在等待,对象A锁中的线程执行完,这时调用notifyAll,是唤醒了对象AB两个锁的全部的等待线程还是只唤醒了A锁的5个线程?

1. 方法文档解释

notifyAll唤醒线程的范围? 通过看该方法文档的解释,可以得出下面结论:

  • notifyAll()中All的含义是所有的线程,而不是所有的锁,只能唤醒等待(调用wait()方法等待)同一个锁的所有线程。notifyAll()执行后,只有一个线程能得到锁,其他没有得到锁的线程会继续保持在等待状态。【notifyAll()只能释放一把锁。】
  • notifyAll()必须在当前线程拥有监视器锁的情况下执行,否则将抛出异常IllegalMonitorStateException。

2. 代码解释

定义两个对象锁,每个对象分别有两个进程,先将对象一里线程A与线程B启动,进入等待状态;在把对象二里的线程C启动,也进入等待状态;接着将对象二里的线程D启动并唤醒其他线程。

package person.xsc.practice;

public class ThreadWaitAndNotifyAll implements Runnable{
        private static Object object1 = new Object();
        private static Object object2 = new Object();
        @Override
        public void run() {
            synchronized (object1) {
                System.out.println(Thread.currentThread().getName() + "获得锁,进入等待状态");
                try {
                    object1.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行最后部分结束");
            }
        }
        public static void main(String[] args) {
            ThreadWaitAndNotifyAll runnable = new ThreadWaitAndNotifyAll();
            Thread threadA = new Thread(runnable,"线程A");
            Thread threadB = new Thread(runnable,"线程B");
            Thread threadC=new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    synchronized (object2) {
                        System.out.println(Thread.currentThread().getName() + "获得锁,进入等待状态");
                        try {
                            object2.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "执行结束");
                    }
                }

            },"线程D");
            Thread threadD = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (object2) {
                        System.out.println(Thread.currentThread().getName() + "获得锁,开始通知唤醒所有线程");
                        // 唤醒其他线程
                        object2.notifyAll();
                        // 调用完notifyAll()方法后,同步代码块中的其他代码,必须执行完后才能将对象锁释放,而不是调用了notifyAll()方法后立即释放。
                        System.out.println(Thread.currentThread().getName() + "执行结束");
                    }
                }
            },"线程C");
            // 每次运行,线程0和线程1的顺序可能会不同,执行顺序由CPU决定
            threadA.start();
            threadB.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadC.start();
            threadD.start();
        }
    }
输出:
线程A获得锁,进入等待状态
线程B获得锁,进入等待状态
线程D获得锁,进入等待状态
线程C获得锁,开始通知唤醒所有线程
线程C执行结束
线程D执行结束

根据上面代码运行结果来看,确实如方法文档所说的那样:notifyAll()只能唤醒等待同一个锁的所有线程。

点赞
收藏
评论区
推荐文章
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
九路 九路
3年前
3 Java对象的内存布局以及对象的访问定位
先来看看Java对象在内存中的布局一Java对象的内存布局在HotSpot虚拟机中,对象在内存中的布局分为3个区域对象头(Header)MarkWord(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储对象自身的运行时数据,包括哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等类型指
Bill78 Bill78
3年前
python中的各种锁
一、全局解释器锁(GIL)  1、什么是全局解释器锁      在同一个进程中只要有一个线程获取了全局解释器(cpu)的使用权限,那么其他的线程就必须等待该线程的全局解释器(cpu)使    用权消失后才能使用全局解释器(cpu),即时多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu,这样的机制称为全局    解释器锁(GIL)。 
Wesley13 Wesley13
3年前
Java并发包小结
1、Lock  Lock功能对应关键字synchrozied功能,lock和unlock方法用于加锁和释放锁。等待锁的线程加入到等待链表中,同时阻塞线程,锁释放时,从等待链表中取出等待的线程执行,取等待的线程分公平与非公平两种方式,公平方式取第一个等待的线程,非公平方式当前正在获取锁的线程可能立刻执行,而不用加入到等待队列中,排队执行。2、Con
Wesley13 Wesley13
3年前
Java并发 wait()、notify()和notifyAll()
一个线程修改一个对象的值,而另一个线程则感知到了变化,然后进行相应的操作,这就是wait()、notify()和notifyAll()方法的本质。具体体现到方法上则是这样的:一个线程A调用了对象obj的wait方法进入到等待状态,而另一个线程调用了对象obj的notify()或者notifyAll()方法,线程A收到通知后从对象obj的wait方法返回,继续
Stella981 Stella981
3年前
Python的锁
互斥锁锁通常被用来实现对共享资源的同步访问。为每一个共享资源创建一个Lock对象,lLock()创建一个锁,初始状态是未锁定当你需要访问该资源时,调用l.acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用l.release方法释放锁!(https:
Wesley13 Wesley13
3年前
Java多线程
wait()方法方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或被中断为止。注意:  在调用wait()之前,线程必须获得该对象的对象级别锁,否则会抛出illegal
Wesley13 Wesley13
3年前
AQS之工作原理
前面一章LZ简单的介绍了下AbstractQueuedSynchronizer(AQS)以及AQS中提供的一些模板方法和作用,这一章LZ将用一个简单的实例来介绍下AQS中独占锁的工作原理。独占锁顾名思义就是在同一时刻只能有一个线程能获取到锁,而其它需要获取这把锁的线程将进入到同步队列中等待获取到了锁的线程释放这把锁,只有获取锁的线程释放了锁,同步队列中的线程
Wesley13 Wesley13
3年前
Java并发编程:Lock
一.synchronized的缺陷synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?  在上面一篇文章中,我们了解到如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁
Wesley13 Wesley13
3年前
Java多线程锁释放
Java多线程运行环境中,在哪些情况下会使对象锁释放?由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:(1)执行完同步代码块,就会释放锁。(synchronized)(2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exc