Java 并发协作 wait、notify、notifyAll 方法

问:简单谈谈 Java 并发协作的 wait、notify、notifyAll 等方法的特点和场景?

答:首先并发协作的 wait、notify、notifyAll 等方法是定义在 Java 的 Object 类中,而非 Thread。wait 有一个重载方法,参数 0 表示无限等待,更重要的是在等待期间均可被中断并抛出 InterruptedException(很重要)。

每个对象都有一把锁和等待队列,线程在进入 synchronized 时,如果尝试获取锁但失败,就会把当前线程加入锁的等待队列,其实每个对象除过有用于锁的等待队列外还有一个条件队列,条件队列就是用来进行线程间的协作的。调用 wait 方法就会把当前线程放入这个条件队列并阻塞,然后等待其他线程通过 notify 或者 notifyAll 触发这个条件(自己无法触发)来执行,惟一的区别就是 notify 会从条件队列选择一个线程触发条件并且从队列移除,而 notifyAll 会触发条件队列里所有等待的线程并从队列移除。

wait 和 notify、notifyAll 只能在 synchronized 函数或者对象中调用,被上锁的对象一般是多线程共享的对象,如果调用 wait 和 notify、notifyAll 方法时当前线程没有持有对象锁则会抛出 IllegalMonitorStateException 异常。

切记:代码执行到 synchronized 锁起来的 wait 方法时当前线程会释放对象锁,因为 wait 的具体实现过程是先把当前线程放入条件等待队列、释放对象锁、阻塞等待(线程状态变为 WAITING 或 TIMED_WATING),等待时间到了或者被其他线程 notify、notifyAll 以后从条件队列中移除。然后要重新竞争对象锁,竞争到就变为 RUNNABLE 状态,否则该线程被加入对象锁队列变为 BLOCKED 状态。

切记:调用 notify、notifyAll 会把条件队列中等待的线程移除但是不会释放对象锁,只有在包含 notify、notifyAll 的 synchronized 方法或者代码块执行完毕才能轮到等待的线程执行。

除了我们要保证 wait 和 notify、notifyAll 应该在 synchronized 块中和那个被多线程共享的对象上调用以外,还要尽可能保证永远在条件循环而不是 if 语句中使用 wait,因为线程从 wait 调用中返回后不代表其等待的条件就一定成立,所以我们在使用 wait 时应该尽量使用如下模板:

        synchronized (sharedObject) {
            while (condition) {
                sharedObject.wait();
                // (Releases lock, and reacquires on wakeup)
            }
            // do action based upon condition e.g. take or put into queue
        }
    }

在条件循环里使用 wait 的目的是在线程被唤醒的前后,都持续检查条件是否被满足,如果条件并未改变而 wait 被调用之前 notify 的唤醒通知就来了,那么这个线程并不能保证被唤醒且有可能会导致死锁问题(建立在全局项目超过两个线程以上)。

譬如假设有两个生产者 A、B,一个消费者 C,在生产消费者模式中如果对生产者 A、B 不使用条件循环而简单 if 判断中调用 wait 就会出事,当空间满了后 A、B 都被 wait,当 C 取走一个数据后如果调用了 notifyAll 则 A、B 都将被唤醒,假设 A 被唤醒后往空间放入一个数据且空间满了,而此时 B 也会放置一个数据,所以发生空间炸裂错误。

(提示:如上也解答了并发的另一个面试题,即 Java 多线程为什么使用 while 循环来调用 wait 方法?)其实 Thread 的 join 方法实现也是条件循环,核心代码是:

while (isAlive()) {
  lock.wait(0);
  }

并发协作其实在 java.util.concurrent 包下已经提供了很多不错且高效的封装实现类了,不过我们依然可以自己使用 wait 和 notify、notifyAll 来解决生产消费者场景、并发等待等场景问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容