Java零基础之多线程篇:线程间如何通信?

news2024/9/20 15:04:53

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

  随着计算机技术的发展,多线程编程已经成为现代软件开发中的一个重要方向。在多线程编程中,线程间的通信是一个非常关键的问题。在Java开发语言中,Java提供了一些机制来实现线程间的通信,帮助开发者协调不同线程之间的执行顺序和数据交换。

摘要

  本文将介绍Java多线程编程中的线程间通信的相关知识。首先,我们将从简介开始,介绍线程间通信的基本概念和原理。然后,我们将通过源代码解析的方式,深入探讨Java中实现线程间通信的方法。接着,我们将给出一些应用场景案例,展示线程间通信在实际开发中的应用。随后,我们将对线程间通信的优缺点进行分析,帮助读者了解线程间通信的适用性。最后,我们将介绍一些常用的类和方法,用于实现线程间通信,并提供具体的Java代码测试用例。全文将以markdown的语法编写,并保证全文内容衔接清晰。

简介

  在多线程编程中,线程是独立的执行单元,它们可以并发地执行任务。然而,在某些情况下,不同线程之间需要进行数据交换或者协作来完成复杂的任务。为了实现线程间的通信,Java提供了以下几种机制:

  1. 共享变量:多个线程共享同一个变量,在访问该变量时需要加锁来保证线程安全。
  2. 管道(Pipe):线程通过管道进行数据通信,其中一个线程作为输入流,另一个线程作为输出流。
  3. 消息队列(MessageQueue):线程通过消息队列进行数据交换,发送方将消息放入消息队列,接收方从消息队列中获取消息。
  4. 信号量(Semaphore):限制同时访问某个资源的线程数量,通过信号量可以实现线程间的同步和互斥。
  5. 读写锁(ReadWriteLock):实现读写分离的锁机制,读操作可以并发执行,写操作需要互斥执行。
  6. 条件(Condition):线程可以根据条件进行等待和唤醒,从而实现线程间的协作。

源代码解析

以下是使用共享变量实现线程间通信的示例代码:

package com.example.javase.ms.threadDemo.day5;

/**
 * @Author ms
 * @Date 2024-04-12 23:00
 */
public class SharedData {
    private int data;
    private boolean isReady = false;

    public synchronized int getData() {
        while (!isReady) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public synchronized void setData(int value) {
        data = value;
        isReady = true;
        notifyAll();
    }

    public static void main(String[] args) {
        SharedData sharedData = new SharedData();
        new Thread(new Reader(sharedData)).start();
        new Thread(new Writer(sharedData)).start();
    }
}

代码分析:

  如上代码,我定义了一个名为SharedData的类,其中包含一个私有的int类型的数据成员data和一个私有的boolean类型的标志成员isReady。还有两个同步方法getData()和setData()。

emsp; 其中getData()方法使用了线程同步,当isReady为false时,使用wait()方法使线程进入等待状态。当isReady为true时,线程被唤醒,并返回data的值。

emsp; setData()方法同样使用了线程同步,它首先将参数value赋值给data,并将isReady设置为true,然后使用notifyAll()方法唤醒所有等待的线程。

emsp; 最后,在main()方法中创建了一个SharedData对象,并创建了两个线程Reader和Writer,分别传入了该SharedData对象作为参数进行操作。

package com.example.javase.ms.threadDemo.day5;

/**
 * @Author ms
 * @Date 2024-04-12 23:01
 */
public class Writer implements Runnable {
    private SharedData sharedData;

    public Writer(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @Override
    public void run() {
        sharedData.setData(10);
        System.out.println("Writer: " + 10);
    }
}

代码分析:

  如上代码,我定义了一个Java线程示例,展示了一个Writer类的实现,实现了Runnable接口。

  在构造方法中,传入了一个SharedData对象,表示要写入的共享数据。

  在run()方法中,通过调用sharedData对象的setData()方法,将数据设置为10,并且使用System.out.println()打印出消息"Writer: 10"。

  该代码的目的是模拟一个写线程,将数据写入共享数据中。

package com.example.javase.ms.threadDemo.day5;

/**
 * @Author ms
 * @Date 2024-04-12 23:00
 */
public class Reader implements Runnable {
    private SharedData sharedData;

    public Reader(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @Override
    public void run() {
        int data = sharedData.getData();
        System.out.println("Reader: " + data);
    }
}

代码分析:

  如上代码,定义了一个名为Reader的类,该类实现了Runnable接口。Reader类有一个成员变量sharedData,它是一个类型为SharedData的对象。

  在Reader类的构造函数中,将SharedData对象作为参数传入,并将其赋值给sharedData成员变量。

  Reader类实现了Runnable接口的run()方法。在run()方法中,通过调用sharedData对象的getData()方法获取数据,并将其赋值给一个int类型的变量data。然后,通过调用System.out.println()方法将数据打印到控制台。

  总的来说,这段代码定义了一个Reader类,用于读取sharedData对象中的数据并输出到控制台。它可以作为一个线程的任务来执行。

小结:

  在上述示例中,Reader线程通过调用getData()方法获取数据,如果数据未准备好,则线程将进入等待状态。Writer线程通过调用setData()方法设置数据,并通知Reader线程数据已准备好。通过共享变量和synchronized关键字,Reader和Writer线程实现了基本的线程间通信。

运行结果展示:

  根据如上用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

应用场景案例

  线程间通信在实际开发中有着广泛的应用,下面是一些常见的应用场景案例:

  1. 生产者-消费者模型:一个或多个生产者线程生产数据,一个或多个消费者线程消费数据,通过共享队列进行数据交换。
  2. 缓存更新:多个线程同时从缓存中获取数据,如果缓存中不存在数据,则需要从数据库中加载数据,并将数据放入缓存。
  3. 任务分配:一个任务队列中有多个待执行的任务,多个线程同时从任务队列中取任务执行,可以通过共享队列和互斥锁实现任务的分配和执行。

优缺点分析

线程间通信有以下优点:

  • 提高并发性:线程间通信可以充分利用计算机的多核处理能力,提高系统的并发性和处理速度。
  • 简化编程模型:线程间通信可以简化编程模型,帮助开发者实现复杂的任务分配和协作逻辑。
  • 提高系统可靠性:线程间通信可以帮助开发者实现线程间的同步和互斥,避免数据竞争和死锁等问题。

然而,线程间通信也存在一些缺点:

  • 复杂性:线程间通信涉及到多个线程的协作和数据交换,需要考虑并发和同步等问题,增加了程序的复杂性和调试的难度。
  • 性能开销:线程间通信需要进行线程切换和数据拷贝等操作,会增加系统的性能开销。
  • 容易出错:线程间通信涉及到共享的状态和资源,如果没有正确处理线程间的同步和互斥,会导致数据不一致和程序错误。

因此,在选择线程间通信的方法时,需要根据具体的需求和场景综合考虑各种因素。

类代码方法介绍

以下是SharedData类的方法介绍:

  • public synchronized int getData(): 获取数据的方法。如果数据未准备好,则线程将进入等待状态,直到数据准备好后返回数据。
  • public synchronized void setData(int value): 设置数据的方法。设置数据后,通知所有等待中的线程数据已准备好。

Java代码测试用例

测试代码演示

  根据如上理论知识,这里我给大家进行一波实例演示,代码如下,仅供参考:

package com.example.javase.ms.threadDemo.day5;

/**
 * @Author ms
 * @Date 2024-04-12 23:06
 */
public class Test {

    public static void main(String[] args) throws InterruptedException {
        SharedData sharedData = new SharedData();
        Thread readerThread = new Thread(new Reader(sharedData));
        Thread writerThread = new Thread(new Writer(sharedData));

        readerThread.start();
        writerThread.start();

        readerThread.join();
        writerThread.join();
    }
}

  在上述测试用例中,我们创建了一个SharedData对象,然后分别创建一个Reader线程和一个Writer线程,并启动它们。最后,我们使用join()方法等待两个线程执行完毕。

测试结果展示

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

测试代码分析

  根据如上代码作出解析,以便于同学们更好的理解,分析如下:

  此段代码是一个多线程编程的示例,其中包含生产者-消费者问题的简化版本。SharedData类模拟了一个共享资源,ReaderWriter类分别模拟消费者和生产者的行为。这段代码没有提供SharedDataReaderWriter类的实现,但基于命名和上下文,我们可以推测它们的功能。

核心概念

  • 生产者-消费者问题:这是一个经典的多线程同步问题,其中生产者创建数据,消费者处理数据。两者需要共享一个有限的缓冲区(或其他形式的共享资源)。生产者在缓冲区有空间时添加数据,而消费者在缓冲区有数据时取出数据。
  • 线程同步:为了确保生产者和消费者能够正确地共享资源,需要使用同步机制来防止数据竞争和确保数据一致性。

代码逻辑

  1. main方法中,创建了一个SharedData实例,它代表共享资源。
  2. 创建了两个线程:readerThreadwriterThreadreaderThread执行Reader类的run方法,而writerThread执行Writer类的run方法。
  3. 使用start()方法启动这两个线程,使它们并发执行。
  4. 使用join()方法等待这两个线程完成。join()方法会阻塞当前线程(在这个例子中是主线程),直到调用join()的线程完成执行。

预期行为

  • Writer线程会尝试向共享资源中添加数据。
  • Reader线程会尝试从共享资源中读取数据。
  • 通过适当的同步机制(在提供的代码片段中未显示),WriterReader会协调它们的操作,以避免数据竞争和潜在的不一致状态。

注意事项

  • 为了确保线程安全,SharedData类中的方法可能需要使用synchronized关键字或其他同步机制。
  • ReaderWriter类中的操作可能需要根据共享资源的状态进行等待或通知,这通常通过wait()notify()notifyAll()方法实现。
  • 异常处理是多线程程序中的一个重要方面。在这个例子中,主线程捕获了InterruptedException,这是在等待线程完成时可能抛出的异常。

结论

  这段代码展示了多线程编程中的一个基本模式,即生产者-消费者问题。为了使程序正确运行,需要确保SharedDataReaderWriter类实现了适当的同步机制。这样的模式在并发编程中非常常见,它有助于理解如何在多线程环境中管理共享资源。

全文小结

  本文介绍了Java多线程编程中的线程间通信的相关知识。我们从简介开始,介绍了线程间通信的基本概念和原理。然后,我们通过源代码解析的方式深入探讨了Java中实现线程间通信的方法。接着,我们给出了一些应用场景案例,展示了线程间通信在实际开发中的应用。随后,我们对线程间通信的优缺点进行了分析,帮助读者了解线程间通信的适用性。

总结

  本文全面探讨了Java多线程编程中线程间通信的概念、原理和实现方法。通过介绍Java提供的多种线程通信机制,如共享变量、管道、消息队列、信号量、读写锁和条件,我们了解了如何协调不同线程的执行顺序和数据交换。文章通过具体的代码示例,详细展示了如何使用共享变量和同步方法在线程间进行通信,以及如何通过wait()notifyAll()方法实现生产者-消费者模型的典型应用。

  文章还提供了线程间通信在实际开发中的应用场景案例,如生产者-消费者模型、缓存更新和任务分配等,这些案例说明了线程通信在解决并发问题中的重要作用。同时,对线程通信的优缺点进行了分析,指出了它在提高系统并发性和简化编程模型的同时,也可能增加程序复杂性和性能开销。

  最后,文章介绍了SharedData类中的getData()setData()方法,并通过一个测试用例展示了如何在实际的Java程序中测试线程间通信。通过这些内容,读者可以更深入地理解线程间通信的工作原理,并能够在自己的项目中有效地实现线程间的协作和数据交换。

  总结来说,线程间通信是多线程编程中不可或缺的一部分,它使得程序能够更有效地利用多核处理器资源,提高程序的执行效率和响应能力。开发者需要根据具体的应用场景和需求,合理选择和使用Java提供的线程通信机制,以确保程序的正确性和高效性。通过不断学习和实践,开发者可以掌握线程间通信的高级技巧,构建更加健壮和可扩展的多线程应用程序。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1973002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机技术基础 (bat 批处理)Note6

计算机技术基础 (bat 批处理)Note6 本节主要讲解FOR命令语句(循环)在 bat 批处理中的使用 (part 2) 变量延迟 命令语句 在没有开启变量延迟的情况下,批处理命令行中的变量改变,必须到下一条命令才能体现…

C++ STL在算法题中的常用语法

Vector 1.将vector<int>中的元素全部置换为0 fill(vec.begin(), vec.end(), 0); 2.vector容器是可以直接用比较是否值等的&#xff01; Unordered_set 1. unordered_set的删除&#xff08;count的值也会减少&#xff09; 2.unordered_map中的int默认值是0&#xff0c;…

Prometheus-v2.45.0+Grafana+邮件告警

目录 普罗米修斯监控架构介绍 Prometheus 监控架构 1. 数据抓取&#xff08;Scraping&#xff09; 2. 时序数据库&#xff08;TSDB&#xff09; 3. 数据模型 4. PromQL 查询语言 5. 告警&#xff08;Alerting&#xff09; 6. Alertmanager 7. 可视化&#xff08;Visu…

从0开始搭建vue + flask 旅游景点数据分析系统( 六):搭建后端flask框架

这一期开始开发header部分&#xff0c;预期实现两个目标&#xff1a; 创建 Flask 项目导入旅游数据后端实现旅游数据的查询 1 python 环境 & 开发环境 python 安装和pycharm安装需要去网上找包&#xff0c;建议python使用3.8 或者3.9版本 2 新建项目 我们新建一个文件…

Kafka详解以及常见kafka基本操作

1、 kafka 是什么,有什么作用 Kafka是一个开源的高吞吐量的分布式消息中间件&#xff0c;对比于缓冲和削峰&#xff1a;上游数据时有突发流量&#xff0c;下游可能扛不住&#xff0c;或者下游没有足够多的机器来保证冗余&#xff0c;kafka在中间可以起到一个缓冲的作用&#x…

Qt项目——文本编辑器(Bug/疑问)

项目地址&#xff1a;GitHub - Outlier9/CatEditor: Cat文本编辑器--Qt 有帮助的话各位点点 star 啦&#xff0c;感谢&#xff01; 如果有需要学习该项目的人&#xff0c;觉得看文档较为困难&#xff0c;可以加我联系方式&#xff0c;给github点个star后可免费提供学习视频&…

红酒与烹饪:美食的灵感之源

在烹饪的广阔天地中&#xff0c;红酒常常作为一道神秘的佐料&#xff0c;为菜肴带来别样的风味与深度。当定制红酒洒派红酒&#xff08;Bold & Generous&#xff09;与烹饪艺术相遇&#xff0c;一场美食的灵感之旅便悄然展开。 一、红酒与烹饪的浪漫邂逅 在烹饪的世界里&…

12月长沙学术会议:EI检索,机器人、自动化与智能控制方向

在春意盎然、生机勃勃的四月&#xff0c;全球科技界的目光聚焦于中国长沙&#xff0c;这里即将迎来一场科技与智慧碰撞的盛宴——第四届机器人、自动化与智能控制国际会议&#xff08;ICRAIC 2024&#xff09;。本次盛会由历史悠久、文化底蕴深厚的湖南第一师范学院荣耀主办&am…

正点原子imx6ull-mini-Linux驱动之platform设备驱动实验(14)

我们在前面几章编写的设备驱动都非常的简单&#xff0c;都是对IO进行最简单的读写操作像I2C、 SPI、LCD 等这些复杂外设的驱动就不能这么去写了&#xff0c;Linux 系统要考虑到驱动的可重用性&#xff0c;因此提出了驱动的分离与分层这样的软件思路&#xff0c;在这个思路下诞生…

QtQuick Text-文本样式

属性 Text项目的style属性可以设置文本的样式。 支持的文本样式有&#xff1a; Text.Normal&#xff08;默认&#xff09;Text.OutlineText.RaisedText.Sunken 示例 import QtQuickRow{spacing: 10padding: 10Text {font.pointSize: 40text: "Normal"}Text {font…

太阳光大约8分钟到达地球?太阳光:我一瞬间就到了!

我们常常听说,太阳光从太阳出发,需要8分钟才能抵达地球。这个时间听起来并不长,但它却是光子在宇宙空间中以惊人速度穿行的见证。 不过,这个8分钟的时间概念,实际上是站在我们地球观察者的角度来说的。如果我们换一个角度,比如说,从光子自己的视角来看待这段旅程,又会是…

2-53 基于matlab的15种图像纹理特征计算

基于matlab的15种图像纹理特征计算。纹理特征包括小梯度优势 T1、大梯度优势 T2、 灰度分布的不均匀性 T3、 梯度分布的不均匀性 T4 、能量 T5、灰度平均 T6、梯度平均 T7、灰度均方差 T8 、梯度均方差 T9、相关 T10 、灰度熵 T11、梯度熵 T12 、 混合熵 T13、惯性 T14 、 逆差…

字符专用输入输出函数 getchar() putchar()

文章目录 一、字符专用接收函数1.1 scanf实现字符接收1.2 字符专用接收函数getchar1.3 练习1.4 利用循环使字符接收函数接收字符串的元素 二、字符专用输出函数2.1 printf实现打印字符2.2 字符专用输出函数putchar 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例…

iOS 系统提供的媒体资源选择器(UIImagePickerController)

简介 图片或者视频的选择功能几乎是每个APP必不可少的&#xff0c;UIImagePickerController 是 iOS 系统提供的一个方便的媒体选择器&#xff0c;允许用户从照片库中选择图片或视频&#xff0c;或者使用相机拍摄新照片和视频。 它的页面简单易用&#xff0c;代码稳定可靠&…

基于STC8H系列单片机的比较器功能调试

基于STC8H系列单片机的比较器功能调试 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单片机管脚图(20个引脚)STC8H系列单片机管脚说明STC8H系列单片机I/O口STC8H系列单片机I…

八股文真的有作用吗?

八股文在实际工作中的作用&#xff1a;助力、阻力还是空谈&#xff1f; 无论如何讨论&#xff0c;八股文都是面试中不可或缺的一环。一般来说&#xff0c;准入门槛是由“招聘”这个“游戏”的设计者设计的&#xff0c;旨在快速高效地筛选出合适的人选。 但是我还是要说&#x…

buu做题(12)

[CISCN 2019 初赛]Love Math <?php error_reporting(0); //听说你很喜欢数学&#xff0c;不知道你是否爱它胜过爱flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c20-1$content $_GET[c];if (strlen($content) > 80) {die("太长了不会算");…

【重磅推出】★全部CFA FRM CAIA ESG原創資料整理[2024版+2025版更新中]

【重磅推出】★全部CFA FRM原創資料整理[2024版2025版更新中] 申明&#xff1a;大部分資料都是本人整理原創內容&#xff0c;最新資料有參考CFA FRM協會&#xff08;有征求協會同意&#xff0c;是可以分享到網上給大家使用的&#xff09;&#xff0c; 去年收集整理了一個帖子&…

抖音小店新宠儿成都夏光汝网络科技

在当今这个数字化时代&#xff0c;电商平台的兴起为无数商家和个人创业者提供了前所未有的机遇&#xff0c;而抖音小店作为抖音平台上的重要电商板块&#xff0c;更是以其庞大的用户基数和高度活跃的社交属性&#xff0c;成为了众多品牌与商家争相入驻的热门选择。其中&#xf…

理学、工学、农学、医学、哲学、经济学、法学、教育学、文学、军事学、管理学、艺术学、历史学等学科的核心思想和基本理论

以下是以表格形式列出的理学、工学、农学、医学、哲学、经济学、法学、教育学、文学、军事学、管理学、艺术学、历史学等学科的核心思想和基本理论&#xff1a; 晓北斗推荐-多学科知识体系 学科核心思想基本理论理学探索自然、社会和人类思维的本质和规律物理学、化学、生物学、…