当前位置: 首页 > news >正文

并发编程 - 线程间三种常见的通信手段

线程间通信是指多个线程之间通过某种机制进行协调和交互,例如:线程等待和通知机制就是线程通讯的主要手段之一。

在 Java 中有以下三种实现线程等待的手段 :

  1. Object 类提供的 wait(),notify() 和 notifyAll() 方法;
  2. Condition 类下的 await(),signal()  和 signalAll() 方法;
  3. LockSupport 类下的 park() 和 unpark() 方法。

第一种方式的代码示例 : 

Object lock = new Object();
new Thread(() -> {synchronized (lock) {try {System.out.println("线程1 -> 进入等待");lock.wait();System.out.println("线程1 -> 继续执行");} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1 -> 执行完成");}
}).start();Thread.sleep(1000);
synchronized (lock) {// 唤醒线程System.out.println("执行 notifyAll()");lock.notifyAll();
}

第二种方式的代码示例 :

// 创建 Condition 对象 (lock 可创建多个 condition 对象)
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 加锁
lock.lock();
try {// 一个线程中执行 await()condition.await();// 另一个线程中执行 signal()condition.signal();
} catch (InterruptedException e) {e.printStackTrace();
} finally {lock.unlock();
}

上述两种线程间通信的方式其实是差不多的,只是 Condition 类它可以创建出多个对象。那为什么有了 Object 类的 wait 和 notify 的方式,还需要 condition 来干嘛呢 ?

答 :因为 Object 类的 wait 和 notify 只适用于一个任务队列,而 Condition 类的 await 和 signal 适用于多个任务队列,在多个任务队列的情况下,使用 Object 类的 wait 和 notify 可能会存在线程饿死的问题。

比如以上这种生产者消费者模型,当生产者,消费者(阻塞式的)都有多个的时候,并且此时任务队列里面没有任务了,所以消费者就会进入休眠状态,此时生产者需要做两件事情 : 

  1. 将任务推送到任务队列
  2. 唤醒线程

【问题所在】

①  此时如果使用 Object 类提供的 wait 和 notify,而唤醒线程是存在两种可能的:

1)唤醒了消费者 

2)唤醒了生产者

        如果是唤醒了生产者,那就出问题了,当生产者这边代码执行完了就结束了,消费者这边永远不会去消费队列里的任务了,这就会导致线程饥饿问题。

②  而 Condition 类因为可以被创建多个,所以可以使用两个 Condition 对象,一个指定唤醒生产者,一个指定唤醒消费者,这样就不会出现线程饥饿了。

【结论】

所以 Condition 类的 await 和 signal 是对 Object 类的 wait 和 notify 的一个补充,它解决了 Object 类种分组不明确的问题。

第三种方式的代码示例:

public static void main(String[] args) {Thread t1 = new Thread(() -> {LockSupport.park();System.out.println("线程1被唤醒");},"线程1");t1.start();Thread t2 = new Thread(() -> {LockSupport.park();System.out.println("线程2被唤醒");},"线程2");t2.start();Thread t3 = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("唤醒线程2");LockSupport.unpark(t2);},"线程3");t3.start();
}

LockSupport 类又是对 Condition 类的一个补充,它可以指定唤醒某一个线程,它解决了前两种方式不能随机指定唤醒线程的问题。

具体使用哪一种,还是要根据业务来进行选择~

http://www.lryc.cn/news/123311.html

相关文章:

  • iperf3命令使用说明
  • 华纳云:美国Linux服务器磁盘分区备份的操作方式
  • Arrays类
  • lua ipairs pairs
  • swift3.0 废弃 swift 4.0 以后字符串截取
  • 休息是不可能休息的
  • Java面向对象(内部类)(枚举)(泛型)
  • macOS - 安装 GNU make、cmake
  • vue中style scoped属性的作用
  • 【ARM 嵌入式 编译系列 10.2 -- 符号表与可执行程序分离详细讲解】
  • Gin各种参数接收
  • 【Python】进阶之 MySQL入门教程
  • Word 2019打开.doc文档后图片和公式不显示(呈现为白框)的解决办法
  • 三个整数排序
  • Nginx反向代理出现错误 502 bad gateway 案例解析
  • 截止到目前全量主体总数有多少?
  • HTTP--Request详解
  • Linux C++ 网络编程基础(2) : TCP多线程一个server对应多个client
  • 如何构建一个 NodeJS 影院微服务并使用 Docker 部署
  • BEVFusion(ICRA-2023)--01
  • Java——Iterator迭代器
  • GCC编译过程:预处理->编译->汇编->链接
  • JVM笔记 —— 出现内存溢出错误时时如何排查
  • 多级嵌套引入组件导致Vue提示子组件未注册问题
  • vue3+element-plus组件下拉列表,数组数据转成树形数据
  • 【kubernetes】调度约束
  • 【深度学习MOT】SMILEtrack SiMIlarity LEarning for Multiple Object Tracking,论文
  • jmeter通过BeanShell对接口参数进行MD5和HmacSHA256加密【杭州多测师_王sir】
  • 基于自适应曲线阈值和非局部稀疏正则化的压缩感知图像复原研究【自适应曲线阈值去除加性稳态白/有色高斯噪声】(Matlab代码实现)
  • Spring AOP 切点表达式