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

Java - 线程间的通信方式

线程通信的方式

线程中通信是指多个线程之间通过某种机制进行协调和交互

线程通信主要可以分为三种方式,分别为共享内存消息传递管道流。每种方式有不同的方法来实现

  • 共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信。
volatile共享内存
  • 消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信。
wait/notify等待通知方式
join方式
  • 管道流
管道输入/输出流的形式


共享内存

/*** @Author: Simon Lang* @Date: 2020/5/5 15:13*/
public class TestVolatile {private static volatile boolean flag=true;public static void main(String[] args){new Thread(new Runnable() {public void run() {while (true){if(flag){System.out.println("线程A");flag=false;}}}}).start();
​
​new Thread(new Runnable() {public void run() {while (true){if(!flag){System.out.println("线程B");flag=true;}}}}).start();}
}
​

测试结果:线程A和线程B交替执行


消息传递-线程等待和通知

线程等待和通知机制是线程通讯的主要手段之一。

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

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

Object 类提供的 wait(),notify() 和 notifyAll() 方法;

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 类下的 await(),signal()  和 signalAll() 方法;

// 创建 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 可能会存在线程饿死的问题。

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

将任务推送到任务队列
唤醒线程
【问题所在】

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

1)唤醒了消费者 

2)唤醒了生产者

        如果是唤醒了生产者,那就出问题了,当生产者这边代码执行完了就结束了,消费者这边永远不会去消费队列里的任务了,这就会导致线程饥饿问题。
而 Condition 类因为可以被创建多个,所以可以使用两个 Condition 对象,一个指定唤醒生产者,一个指定唤醒消费者,这样就不会出现线程饥饿了。

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

LockSupport 类下的 park() 和 unpark() 方法。

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 类的一个补充,它可以指定唤醒某一个线程,它解决了前两种方式不能随机指定唤醒线程的问题。

join方式

join()方法的作用是:在当前线程A调用线程B的join()方法后,会让当前线程A阻塞,直到线程B的逻辑执行完成,A线程才会解除阻塞,然后继续执行自己的业务逻辑,这样做可以节省计算机中资源。

public class TestJoin {public static void main(String[] args){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程0开始执行了");}});thread.start();for (int i=0;i<10;i++){JoinThread jt=new JoinThread(thread,i);jt.start();thread=jt;}
​}
​static class JoinThread extends Thread{private Thread thread;private int i;
​public JoinThread(Thread thread,int i){this.thread=thread;this.i=i;}
​@Overridepublic void run() {try {thread.join();System.out.println("线程"+(i+1)+"执行了");} catch (InterruptedException e) {e.printStackTrace();}}}
}
​

每个线程的终止的前提是前驱线程的终止,每个线程等待前驱线程终止后,才从join方法返回,实际上,这里涉及了等待/通知机制,即下一个线程的执行需要接受前驱线程结束的通知。


管道输入/输出流

管道流是是一种使用比较少的线程间通信方式,管道输入/输出流和普通文件输入/输出流或者网络输出/输出流不同之处在于,它主要用于线程之间的数据传输,传输的媒介为管道。

管道输入/输出流主要包括4种具体的实现:PipedOutputStrean、PipedInputStrean、PipedReader和PipedWriter,前两种面向字节,后两种面向字符。

java的管道的输入和输出实际上使用的是一个循环缓冲数组来实现的,默认为1024,输入流从这个数组中读取数据,输出流从这个数组中写入数据,当这个缓冲数组已满的时候,输出流所在的线程就会被阻塞,当向这个缓冲数组为空时,输入流所在的线程就会被阻塞。

public class TestPip {public static void main(String[] args) throws IOException {PipedWriter writer  = new PipedWriter();PipedReader reader = new PipedReader();//使用connect方法将输入流和输出流连接起来writer.connect(reader);Thread printThread = new Thread(new Print(reader) , "PrintThread");//启动线程printThreadprintThread.start();int receive = 0;try{//读取输入的内容while((receive = System.in.read()) != -1){writer.write(receive);}}finally {writer.close();}}
​private static class Print implements Runnable {private PipedReader reader;
​public Print(PipedReader reader) {this.reader = reader;}
​@Overridepublic void run() {int receive = 0;try{while ((receive = reader.read()) != -1){//字符转换System.out.print((char) receive);}}catch (IOException e) {System.out.print(e);}}}
}
​

 对于Piped类型的流,必须先进性绑定,也就是调用connect()方法,如果没有将输入/输出流绑定起来,对于该流的访问将抛出异常。

相关文章:

Java - 线程间的通信方式

线程通信的方式 线程中通信是指多个线程之间通过某种机制进行协调和交互 线程通信主要可以分为三种方式&#xff0c;分别为共享内存、消息传递和管道流。每种方式有不同的方法来实现 共享内存&#xff1a;线程之间共享程序的公共状态&#xff0c;线程之间通过读-写内存中的公…...

【计算机网络】HTTP响应报文Cookie原理

目录 HTTP响应报文格式 一. 状态行 状态码与状态码描述 二. 响应头 Cookie原理 一. 前因 二. Cookie的状态管理 结束语 HTTP响应报文格式 HTTP响应报文分为四部分 状态行&#xff1a;包含三部分&#xff1a;协议版本&#xff0c;状态码&#xff0c;状态码描述响应头&a…...

2023年度盘点:智能汽车、自动驾驶、车联网必读书单

【文末送书】今天推荐几本自动驾驶领域优质书籍 前言 2023年&#xff0c;智能驾驶和新能源汽车行业仍然有着肉眼可见的新进展。自动驾驶技术继续尝试从辅助驾驶向自动驾驶的过渡&#xff0c;更重要的是相关技术成本的下降。根据《全球电动汽车展望2023》等行业报告&#xff0c…...

一文讲解如何从 Clickhouse 迁移数据至 DolphinDB

ClickHouse 是 Yandex 公司于2016年开源的 OLAP 列式数据库管理系统&#xff0c;主要用于 WEB 流量分析。凭借面向列式存储、支持数据压缩、完备的 DBMS 功能、多核心并行处理的特点&#xff0c;ClickHouse 被广泛应用于广告流量、移动分析、网站分析等领域。 DolphinDB 是一款…...

[足式机器人]Part2 Dr. CAN学习笔记-数学基础Ch0-5Laplace Transform of Convolution卷积的拉普拉斯变换

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-数学基础Ch0-5Laplace Transform of Convolution卷积的拉普拉斯变换 Laplace Transform : X ( s ) L [ x ( t ) ] ∫ 0 ∞ x ( t ) e − s t d t X\left( s \right) \mathcal{L} \left[ x\lef…...

生产问题: 利用线程Thread预加载数据缓存,其它类全局变量获取缓存偶发加载不到

生产问题: 利用线程Thread预加载数据缓存偶发加载不到 先上代码 public class ThreadTest {//本地缓存Map<String, Object> map new HashMap<String, Object>();class ThreadA implements Runnable{Overridepublic void run() {System.out.println("Thread…...

Elasticsearch mapping 之 性能相关配置

ES 常见类型 通用类型: 二进制: binary 布尔型: boolean 字符串: keyword, constant_keyword, wildcard, text 别名: alias 对象: object, flattened, nested, join 结构化数据类型: Range, ip, version, murmur3 空间数据类型: geo_point, geo_shape, point, shape 性…...

adb push报错:remote couldn‘t create file: Is a directory

adb push报错&#xff1a;remote couldn‘t create file: Is a directory 出现这个问题可能是电脑本地目录中包含中文或者是目录地址中多包含了一个/ 比如说以下两种路径 1. test/测试音频文件1/a.mp3 2.test/test_audio/ 这两种都是不可以的&#xff08;我是在as中执行的…...

GitLab 服务更换了机器,IP 地址或域名没有变化时,可能会出现无法拉取或提交代码的情况。

当 GitLab 服务更换了机器&#xff0c;但 IP 地址或域名没有变化时&#xff0c;可能会出现无法拉取或提交代码的情况。 这可能是由于 SSH 密钥或 SSL 证书发生了变化。以下是一些可能的解决步骤&#xff1a; 这可能是由于 SSH 密钥或 SSL 证书发生了变化。以下是一些可能的解决…...

【华为OD题库-076】执行时长/GPU算力-Java

题目 为了充分发挥GPU算力&#xff0c;需要尽可能多的将任务交给GPU执行&#xff0c;现在有一个任务数组&#xff0c;数组元素表示在这1秒内新增的任务个数且每秒都有新增任务。 假设GPU最多一次执行n个任务&#xff0c;一次执行耗时1秒&#xff0c;在保证GPU不空闲情况下&…...

持续集成交付CICD:Jenkins使用GitLab共享库实现前后端项目Sonarqube

目录 一、实验 1.Jenkins使用GitLab共享库实现后端项目Sonarqube 2.优化GitLab共享库 3.Jenkins使用GitLab共享库实现前端项目Sonarqube 4.Jenkins通过插件方式进行优化 二、问题 1.sonar-scanner 未找到命令 2.npm 未找到命令 一、实验 1.Jenkins使用GitLab共享库实现…...

Linux文件结构与文件权限

基于centos了解Linux文件结构 了解一下文件类型 Linux采用的一切皆文件的思想&#xff0c;将硬件设备、软件等所有数据信息都以文件的形式呈现在用户面前&#xff0c;这就使得我们对计算机的管理更加方便。所以本篇文章会对Linux操作系统的文件结构和文件权限进行讲解。 首先…...

CentOS上安装和配置Apache HTTP服务器

在CentOS系统上安装和配置Apache HTTP服务器可以为您的网站提供可靠的托管环境。Apache是开源的Web服务器软件&#xff0c;具有广泛的支持和强大的功能。下面是在CentOS上安装和配置Apache HTTP服务器的步骤&#xff1a; 步骤一&#xff1a;安装Apache HTTP服务器 打开终端&am…...

前端知识(十二)———ES6迭代器

ES6中的迭代器是一种新的对象&#xff0c;它具有一个next()方法。next()方法返回一个对象&#xff0c;这个对象包含两个属性&#xff1a;value和done。value属性是迭代器中的下一个值&#xff0c;done属性是一个布尔值&#xff0c;表示迭代器是否已经遍历完所有的值。迭代器是一…...

云端仓库平台

SpringBoot MySQL Vue 等技术实现的云端仓库 技术栈 核心框架&#xff1a;SpringBoot 持久层框架&#xff1a;MyBatis-Plus 前端框架&#xff1a;Vue 数据库&#xff1a;MySQL 项目包含源码和数据库文件。 效果图如下&#xff1a;...

php第三方skd自动加载

把mugou-sdk复制到项目下在composer.josn找到classmap加入sdk "autoload": {"classmap": ["mugou-sdk"] },在composer.josn找到files加入sdk "autoload": {"files":[mugou-sdk] },项目目录下运行 composer dump-autoload…...

Golang channle(管道)基本介绍、快速入门

channel(管道)-基本介绍 为什么需要channel&#xff1f;前面使用全局变量加锁同步来解决goroutine的通讯&#xff0c;但不完美 1)主线程在等待所有goroutine全部完成的时间很难确定&#xff0c;我们这里设置10秒&#xff0c;仅仅是估算。 2)如果主线程休眠时间长了&#xff0c…...

盘点六款颇具潜力的伪原创AI工具

写作作为信息传递的主要媒介&#xff0c;在庞大的信息海洋中&#xff0c;为了在激烈的竞争中脱颖而出&#xff0c;伪原创AI工具成为越来越多写手的神秘利器。在本文中&#xff0c;我们将深入盘点六款颇具潜力的伪原创AI工具&#xff0c;为你揭开它们神秘的面纱。 1. 文心一言 …...

基于SSM的健身房预约系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

postgresql自带指令命令系列二

简介 在安装postgresql数据库的时候会需要设置一个关于postgresql数据库的PATH变量 export PATH/home/postgres/pg/bin:$PATH&#xff0c;该变量会指向postgresql安装路径下的bin目录。这个安装目录和我们在进行编译的时候./configure --prefix [指定安装目录] 中的prefix参…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...