线程通信的几种方式

线程是如何通讯的? 线程通讯指的是多个线程之间通过共享内存或消息传递等方式来协调和同步它们的执行。在多线程编程中,通常会出现多个线程需要共同完成某个任务的情况,这时就需要线程之间进行通讯,以保证任务能够顺利地执行。线程通讯的实现方式主要有以下两种:共享内存:多个线程可以访问同一个共享内存区域,通过读取和写入内存中的数据来进行通讯和同步。消息传递:多个线程之间通过消息队列、管道、信号量等机制来传递信息和同步状态。 阅读详情
AI摘要

本文介绍了Java中多种线程通信的方式,包括使用volatile关键字、Object类的wait()/notify()方法、CountDownLatch计数器、ReentrantLock结合Condition条件变量、LockSupport阻塞唤醒工具等,帮助读者理解不同场景下的线程协作。

一、问题

有两个线程,A 线程向一个集合里面依次添加元素“abc”字符串,一共添加十次,当添加到第五次的时候,希望 B 线程能够收到 A 线程的通知,然后 B 线程执行相关的业务操作。线程间通信的模型有两种:共享内存和消息传递,以下方式都是基于这两种模型实现的。

二、volatile关键字:基于共享内存

多个线程同时监听一个变量,当该变量发生变化的时候,线程能够感知并执行相应的业务。这是最简单的一种实现方式:

public class TestSync {
    //定义共享变量来实现通信,它需要volatile修饰,否则线程不能及时感知
    static volatile boolean notice = false;

    public static void main(String[] args) {
        List<String>  list = new ArrayList<>();
        //线程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A添加元素,此时list的size为:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    notice = true;
            }
        });
        //线程B
        Thread threadB = new Thread(() -> {
            while (true) {
                if (notice) {
                    System.out.println("线程B收到通知,开始执行自己的业务...");
                    break;
                }
            }
        });
        //需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再启动线程A
        threadA.start();
    }
}

三、Object 类的 wait()/notify()

Object类提供了线程间通信的方法:wait()、notify()、notifyAll(),它们是多线程通信的基础,而这种实现方式的思想自然是线程间通信。

注意:wait()/notify()/notifyAll() 必须配合 synchronized 使用,wait 方法释放锁,notify 方法不释放锁。wait 是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify()notify并不释放锁,只是告诉调用过wait()的线程可以去参与获得锁的竞争了,但不会马上得到锁,因为锁还在别人手里,别人还没释放,调用 wait() 的一个或多个线程才会解除 wait 状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

public class TestSync {
    public static void main(String[] args) {
        //定义一个锁对象
        Object lock = new Object();
        List<String>  list = new ArrayList<>();
        // 线程A
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                for (int i = 1; i <= 10; i++) {
                    list.add("abc");
                    System.out.println("线程A添加元素,此时list的size为:" + list.size());
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (list.size() == 5)
                        lock.notify();//唤醒B线程
                }
            }
        });
        //线程B
        Thread threadB = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    if (list.size() != 5) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("线程B收到通知,开始执行自己的业务...");
                }
            }
        });
        //需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再启动线程A
        threadA.start();
    }
}

由输出结果,在线程 A 发出 notify() 唤醒通知之后,依然是走完了自己线程的业务之后,线程 B 才开始执行,正好说明 notify() 不释放锁,而 wait() 释放锁。

四、JUC工具类CountDownLatch

jdk1.5之后在java.util.concurrent包下提供了很多并发编程相关的工具类,简化了并发编程代码的书写,CountDownLatch 基于AQS框架,相当于也是维护了一个线程间共享变量 state。

public class TestSync {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        List<String>  list = new ArrayList<>();
        //线程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A添加元素,此时list的size为:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    countDownLatch.countDown();
            }
        });
        //线程B
        Thread threadB = new Thread(() -> {
            while (true) {
                if (list.size() != 5) {
                    try {
                        countDownLatch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程B收到通知,开始执行自己的业务...");
                break;
            }
        });
        //需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再启动线程A
        threadA.start();
    }
}

五、ReentrantLock结合 Condition

public class TestSync {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        List<String> list = new ArrayList<>();
        //线程A
        Thread threadA = new Thread(() -> {
            lock.lock();
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A添加元素,此时list的size为:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    condition.signal();
            }
            lock.unlock();
        });
        //线程B
        Thread threadB = new Thread(() -> {
            lock.lock();
            if (list.size() != 5) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程B收到通知,开始执行自己的业务...");
            lock.unlock();
        });
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadA.start();
    }
}

这种方式使用起来并不是很好,代码编写复杂,而且线程 B 在被 A 唤醒之后由于没有获取锁还是不能立即执行,也就是说,A 在唤醒操作之后,并不释放锁。这种方法跟 Object 的 wait()/notify() 一样。

六、基本 LockSupport 实现线程间的阻塞和唤醒

LockSupport 是一种非常灵活的实现线程间阻塞和唤醒的工具。使用它不用关注是等待线程先进行还是唤醒线程先运行,但是得知道线程的名字。

public class TestSync {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //线程B
        final Thread threadB = new Thread(() -> {
            if (list.size() != 5) {
                LockSupport.park();
            }
            System.out.println("线程B收到通知,开始执行自己的业务...");
        });
        //线程A
        Thread threadA = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                list.add("abc");
                System.out.println("线程A添加元素,此时list的size为:" + list.size());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (list.size() == 5)
                    LockSupport.unpark(threadB);
            }
        });
        threadA.start();
        threadB.start();
    }
}
线程之间的通信 目录什么是线程之间的通信线程之间的通信如何实现`join()` 什么是线程之间的通信 线程一旦开始运行,就会拥有自己独立的栈空间,那多个线程如何相互配合完成工作,这就涉及到了线程间的通信 线程之间的通信:是使线程间能够互相发送信号,使线程能够等待其他线程的信号。比如线程 A 在执行到某个条件时,通知线程 B 再执行某个操作,我们希望多个线程协同工作来完成某个任务 线程之间的通信如何实现 join() 需求说明:假设有 A,B,C 三个线程,要求三个线程分别依次打印 1~3 三个数字。 针对这个需求,要求线程 阅读详情

相关推荐

C++ 并发编程指南(10)线程间通信

在多线程编程中,线程间通信(Inter-Thread Communication,简称ITC)是不可或缺的一部分,它使得不同的线程能够交换信息、协作完成任务。C++作为一种功能强大的编程语言,提供了多种机制来实现线程间的通信。下面我们将详细讨论这些机制。

个人技术博客 1万+

线程间通讯(几种常见的通讯机制,以及实例)

介绍线程间通讯的几种方式,以及一些实例

bigger_belief的博客 1万+

java实现线程通信的几种方式

前言 在多线程的世界里,线程与线程之间的交互无处不在,只不过在平时的开发过程中,大多数情况下,我们都在单线程的模式下进行编码,即使有,也直接借助框架自身的机制实现了,其实线程之间的通信在JDK中是一个比较深的问题,比如大家熟知的消息中间件的实现,从某种角度上讲,就借助了多线程通信的思想,下面总结了JDK中常用的几种实现线程通信的方式,提供参考 1、synchronized实现方式 可能很多小伙伴们会有疑问,synchronized是对共享资源加锁使用的,怎么和线程通信扯在一起呢?这里纠正一个小小的偏见,也是

congge 5万+

线程通信的四种方式

多个线程在并发执行的时候,他们在CPU中是随机切换执行的,这个时候我们想多个线程一起来完成一件任务,这个时候我们就需要线程之间的通信了,多个线程一起来完成一个任务,线程通信一般有4种方式: 通过 volatile 关键字 通过 Object类的 wait/notify 方法 通过 condition 的 await/signal 方法 通过 join 的方式 现在有一个问题,两个线程分别打印字符串,但是当线程A每输出两次的时候,线程B就输出一次,如此反复10次。 通过 volatile 关键字 通过

weixin_43786099的博客 3万+

【IC设计实战】去耦电容decap在电源完整性中的关键作用与选型策略

本文深入探讨了去耦电容(decap)在IC设计电源完整性中的核心作用。文章分析了decap如何通过提供本地电荷缓冲来抑制电源噪声与电压波动,并详细阐述了其选型与布局策略,包括MIM、MOM、MOS电容的特性对比,以及如何权衡峰值抑制与建立速度的矛盾,为设计稳定可靠的芯片电源系统提供实践指导。

weixin_29233857的博客 248

初学者入门机器学习 (ML)的推荐教程

了解基本的机器学习概念并不难。有大量免费的在线博客文章、视频和编码教程可以引导您了解基础知识——从介绍性内容到常见应用程序,再到算法和应用技能。这篇文章总结了一些用于介绍 ML 的最佳免费选项。它按逻辑顺序排列,每个概念都建立在上一个概念的基础上。

u010542847的博客 4617

线程之间的通信方式

前言 我只是个搬运工,尊重原作者的劳动成果,本文来源下列文章链接: https://zhuanlan.zhihu.com/p/129374075 https://blog.youkuaiyun.com/jisuanji12306/article/details/86363390 线程之间为什么要通信? 通信的目的是为了更好的协作,线程无论是交替式执行,还是接力式执行,都需要进行通信告知。首先,要短信线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析: 题目

weixin_41979002的博客 7139

嵌入式软件面试常见问题及答案

干了多年的嵌入式,被面试过,也面过不少新人,下面这些是面试中很常见的一些问题及答案,答案可以根据自己的经验自己思考下。--持续补充并更新

weixin_37553721的博客 6023

线程间通信的几种实现方式

线程间通信的几种实现方式 首先,要短信线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析: 题目:有两个线程A、B,A线程向一个集合里面依次添加元素&amp;quot;abc&amp;quot;字符串,一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作。 方式一:使用 volatile 关键字 基于 volatile...

InterfaceJ的博客 18万+

【模拟电子设计实战】开源!基于Multisim与AD620的心电采集电路仿真与优化

本文详细介绍了基于Multisim与AD620的心电采集电路仿真与优化实战。通过分析心电信号采集的挑战,重点讲解了AD620仪表放大器和OP07运算放大器的选型优势及电路设计技巧,包括对抗50Hz工频干扰和基线漂移的优化方法。文章还分享了Multisim仿真参数设置与实测对比经验,最终实现性能达标的心电采集电路设计。

weixin_30555125的博客 95

多智能体协作的本质是中介者模式,不是多开Agent

多智能体系统并非简单启动多个Agent实例,而是一种受控的、可验证的动态交互过程。其核心原理在于解耦Agent间直接依赖,通过中央中介者统一管理任务分发、协议转换、状态协调与故障兜底。这种架构显著提升系统的可观测性、容错性与可维护性,技术价值体现在强一致性保障(如金融订单原子操作)与灵活自治平衡(如边缘设备轻量协同)。典型应用场景包括电商客服协同、工业巡检调度、飞书/微信多渠道智能服务等。OpenClaw与Hermes Agent正是这一范式的工程落地代表,分别体现强中介与弱中介两种演进路径。

weixin_34151004的博客 359

线程之间的几种通信方式

一、线程之间的几种通信方式 1、管道,是一种半双工方式,数据单方向流动,而且只能在有亲缘关系的线程之间使用。他是基于内核的,可以把它当作是内核缓冲区,在内核和用户空间交换数据需要进行四次的数据拷贝,因为他是把用户空间的数据拷贝到内核,然后从内核拷贝到内存,然后从内存再拷贝到内核,最后拷贝到用户空间,至于为什么要拷贝到内核,是因为数据最重都是在内存中执行的。接收的时候要按照次序,按照先进先出的原则,在管道中的数据只能被读取1次,读出之后缓冲区就不存在了。它只能承载没有格式的字节流 。 2、命名管道,和管道差不

qq_44688861的博客 1万+

CNN+LSTM+Attention+DNN模型实战:pytorch搭建CNN+LSTM+Attention+DNN行车速度预测

CNN+LSTM+Attention+DNN模型实战:pytorch搭建CNN+LSTM+Attention+DNN行车速度预测

6045

线程的几种通信方式

目录 一、Object的wait()、notify()、notifyAll()方法 二、Condition的await()、signal()、signalAll()方法 三、CountDownLatch 四、CyclicBarrier 五、Semaphore 线程间的通信方式常用的有如下几种: Object的wait()、notify()、notifyAll()方法; Condi...

Hi_Red_Beetle的博客 2208

Copilot在游戏开发中的应用:Unity脚本自动生成实践

2021年GitHub Copilot的发布,为代码自动生成带来了革命性突破。作为基于GPT模型训练的AI辅助编程工具,Copilot能根据注释、函数名、代码上下文,实时生成符合语法和逻辑的代码片段,甚至完整脚本。减少重复劳动:自动生成模板代码(如生命周期、结构),让你专注核心逻辑;降低API学习成本:对Unity特有的组件(RigidbodyAnimator)、类(),Copilot能生成符合最佳实践的调用代码;统一代码风格:通过团队共享提示词模板,让生成的代码符合项目规范;快速原型迭代。

AIGC应用创新大全的博客 1618

#systemverilog# 之 event region 和 timeslot 仿真调度(三)Verdi 辅助查看

通过今天的学习,我们知道:event region 是event sequence 的全集。我们打开了 event region feature 也就开启了event sequence 的功能。

那么菜的博客 1365

进程间的几种通信方式的比较和线程间的几种通信方式

近日想总结下进程间,线程间的通信方式,在网上搜索了下,感觉写的很好,照搬过来,当做加深记忆。 几种进程间的通信方式 (1) 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。 (2)有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。 (3)信号量(semopho

ykc的专栏 3万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

进程和线程的几种通信方式

进程之间通信的几种方式和线程之间的通信方式,以及Java中创建多线程的几种方式

weixin_40701758的博客 7429

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

python 线程通信的几种方式_进程间通信和线程间通信的几种方式

进程进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念...

weixin_39862899的博客 1680

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java线程通信的几种方式

有两个线程,A 线程向一个集合里面依次添加元素“abc”字符串,一共添加十次,当添加到第五次的时候,希望 B 线程能够收到 A 线程的通知,然后 B 线程执行相关的业务操作。线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。基于 volatile 关键字来实现线程间相互通信是使用共享内存的思想。大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式 Object 类提供了线程间通信的方法:wait()、no

Admans的专栏 4922

java线程通信的几种方式_Java线程间通信的几种方式

文章目录一、使用同一个共享变量控制Synchronized、wait、notifypublic class Demo1 {private final List list =new ArrayList<>();public static void main(String[] args) {Demo1 demo =new Demo1();new Thread(()->{for (in...

weixin_30018111的博客 519

线程间实现通信的几种方式

线程间通信的模型有两种:共享内存和消息传递,下面介绍的都是围绕这两个来实现有两个线程A和B,B线程向一个集合里面依次添加元素“abc”字符串,一共添加10次,当添加到第五次的时候,希望线程A能够收到线程B的通知,然后B线程执行相关的业务操作Object类提供了线程间通信的方法:wait()、notify()、notifyAll(),它们是多线程通信的基础,而这种实现方式的思想自然是线程间通信。 线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list

weixin_54046648的博客 4303

android 线程间通信几种方式

1.共享变量(内存) 2.管道 3.handle机制 runOnUiThread(Runnable) view.post(Runnable)

shunjianopo的博客 3185
上一篇: 如何确保三个线程顺序执行
下一篇: Spring中@Async
JFS_Study
博客等级 码龄6年 363粉丝 359原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值