前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java线程等待、唤醒通信机制详解

Java线程等待、唤醒通信机制详解

作者头像
JavaEdge
发布2022-11-30 15:19:33
7340
发布2022-11-30 15:19:33
举报
文章被收录于专栏:JavaEdgeJavaEdge

要想实现多个线程之间的协同,如:线程执行先后顺序、获取某个线程执行的结果等。 涉及到线程之间相互通信,分为如下四类:

1 文件共享

2 网络共享

socket编程

3 共享变量

4 线程协作(JDK API)

细分为: suspend/resume 、 wait/notify、 park/unpark

JDK中对于需要多线程协作完成某一任务的场景,提供了对应API支持。 多线程协作的典型场景是:生产者-消费者模型。(线程阻塞、 线程唤醒)

示例

  • 线程-1去买包子,没有包子,则不再执行
  • 线程-2生产出包子,通知线程-1继续执行

4.1 suspend、resume(废弃)

  • 调用suspend挂起目标线程
  • resume恢复线程执行

但该组合很容易写出

死锁

  • 同步代码中使用
  • 先后顺序:suspend比resume后执行

所以用如下机制替代

4.2 wait/notify

这些方法只能由同一对象锁的持有者线程调用,即写在同步块里!否则抛IllegalMonitorStateException。

wait 方法导致当前线程等待,加入该对象的等待集合中,并且放弃当前持有的对象锁

notify/notifyAll 方法唤醒一个/所有正在等待这个对象锁的线程。

虽然wait会自动解锁,但对顺序有要求。若在notify被调用后, 才调用wait,则线程会永远处于WAITING态。

正常使用

死锁

synchronized 或 lock

线程先要获得并持有锁,必须在锁块(synchronized或lock)中。必须要先等待后唤醒,线程才能够被唤醒。

park/unpark

LockSupport用来创建锁和其他同步类的基本线程阻塞原语:

  • 线程调用LockSupport.park,则等待“许可”
  • 线程调用LockSupport.unpark,必须把等待获得许可的线程作为参数进行传递,好让此线程继续运行,为指定线程提供“许可(permit)”

不要求park和unpark方法的调用顺序,无需写在任何同步代码块里。

多次调用unpark之后,再调用park,线程会直接运行,不会叠加,累加上限只有 1,即连续多次调用park,第一次会拿到“许可”直接运行,后续调用还是会进入等待。

正常

死锁

5 伪唤醒

之前代码中用if语句来判断,是否进入等待状态,是错误的

官方推荐应该在循环中检查等待条件,因为处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就可能在没有满足结束条件的情况下退出。

伪唤醒是指线程并非因为notify、notifyall、 unpark等API调用而唤醒,而是更底层原因导致的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 文件共享
  • 2 网络共享
  • 3 共享变量
  • 4 线程协作(JDK API)
    • 示例
      • 4.1 suspend、resume(废弃)
        • 死锁
      • 4.2 wait/notify
        • 正常使用
        • 死锁
      • synchronized 或 lock
        • park/unpark
          • 正常
          • 死锁
      • 5 伪唤醒
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档