滚雪球学Java(82):快速上手Java线程通信:零基础学习指南

  咦咦咦,各位小可爱,我是你们的好伙伴 bug菌,今天又来给大家手把手教学Java SE系列知识点啦,赶紧出来哇,别躲起来啊,听我讲干货记得点点赞,赞多了我就更有动力讲得更欢哦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~


🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

前言

  日常开发中,少不了多线程相关编写,对于线程间的通信,它就是一个重要的概念。线程通信能够确保了多个线程可以协同工作,共享数据,并在必要时相互等待或通知。而今天,我就是要给大家介绍Java中线程通信的基本概念、方法和应用场景,旨在帮助Java小白理解和掌握线程通信的技巧。

摘要

  首先对于线程通信,它允许不同线程之间进行数据的交换和同步。在Java中,线程通信可以通过共享对象的方式来实现,通过使用共享对象的waitnotifynotifyAll方法,线程之间可以实现等待唤醒的操作,从而实现线程之间的协调与合作。

概述

  在多线程编程中,线程之间的通信是非常常见的场景之一了。例如,一个线程可能需要等待另一个线程完成某个操作后才能继续执行,或者多个线程之间需要共享某个变量。线程通信可以有效地解决这些问题,使得多线程编程更加灵活和高效,那具体如何解决呢?

  看这里,Java提供了几种机制来实现线程通信,其中最常用的是使用共享对象的waitnotifynotifyAll方法。wait方法使得当前线程进行等待,直到其他线程调用该对象的notifynotifyAll方法才能将它唤醒;notify 方法作用是用于唤醒等待在该对象上的一个线程;而notifyAll方法则是用于唤醒等待在该对象上的所有线程,大白话就是唤醒单复数的意思。

Java之线程通信

源代码解析

  这里,开局来段示例代码(so easy!),给大家演示下线程通信的基本用法,同学们瞧好了:

  我们先来定义一个启动类,展示如何在Java中创建和管理线程,以及如何通过共享资源来实现线程间的协作。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-03 18:37
 */
public class ThreadCommunicationExample {
    public static void main(String[] args) {
        //模拟了一个生产者-消费者场景
        final Processor processor = new Processor();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    processor.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  其次,这里我们再来定义一个模拟生产者-消费者场景的类,然后分别定义一个生产者类跟消费者类。

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-03 18:37
 */
public class Processor {
    
    public void produce() throws InterruptedException {
        synchronized (this) {
            System.out.println("Producer thread running...");
            wait();
            System.out.println("Producer thread resumed...");
        }
    }

    public void consume() throws InterruptedException {
        Thread.sleep(2000);

        synchronized (this) {
            System.out.println("Consumer thread running...");
            notify();
            Thread.sleep(5000);
        }
    }
}

  在这个示例中,有两个线程:一个生产者线程和一个消费者线程。生产者线程在synchronized块中调用了wait方法,进入等待状态;而消费者线程在synchronized块中调用了notify方法,唤醒了生产者线程。

  实际执行结果展示如下:

应用场景案例

  然后经过上述简单演示,这里再给大家介绍下线程通信在实际开发中的一些应用场景。以下是一些常见的应用场景案例:

  1. 生产者-消费者模型:多个生产者线程和多个消费者线程之间通过共享对象进行数据交换,实现生产者和消费者的协作。
  2. 售票系统:多个售票窗口同时售卖车票,通过线程通信来避免多个窗口同时售卖同一张车票。
  3. 线程池:线程池中的多个工作线程之间需要协调工作,通过线程通信来实现任务的分配和执行。
  4. 消息队列:多个生产者线程将消息放入队列,多个消费者线程从队列中取出消息,通过线程通信来实现生产者和消费者之间的交互。

优缺点分析

  线程通信的优点是可以使多个线程之间能够协调工作,实现数据的交换和同步。它能够提高程序的并发性和效率,提高系统的吞吐量。

  然而,任何事物都有优劣性;对于线程通信也有一些缺点。首先,使用线程通信机制会增加程序的复杂性,需要仔细设计和实现。其次,线程通信可能会引发一些常见的并发问题,如死锁和竞态条件。因此,在使用线程通信时需要注意相关的并发问题,并进行适当的同步和锁定操作。

类代码方法介绍

Processor类

produce方法
public void produce() throws InterruptedException {
    synchronized (this) {
        System.out.println("Producer thread running...");
        wait();
        System.out.println("Producer thread resumed...");
    }
}

  produce()方法是一个生产者方法,通过synchronized关键字实现对共享对象的互斥访问。在方法内部使用wait方法使得当前线程进入等待状态,并释放对该对象的锁定。当其他线程调用该对象的notify或notifyAll方法时,该线程会被唤醒并继续执行。

consume方法
public void consume() throws InterruptedException {
    Thread.sleep(2000);

    synchronized (this) {
        System.out.println("Consumer thread running...");
        notify();
        Thread.sleep(5000);
    }
}

  consume方法是一个消费者方法,通过synchronized关键字实现对共享对象的互斥访问。在方法内部使用notify方法唤醒等待在该对象上的一个线程。注意,notify方法不会释放对该对象的锁定,直到执行完synchronized块才会释放。

测试用例

测试代码

  如下我给大家简单演示下如何验证线程通信的功能,如下是一个简单的测试用例(实则不简单),仅供参考:

/**
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2024-04-03 18:52
 */
public class Test {

    public static void main(String[] args) throws InterruptedException {
        // 创建一个有界阻塞队列,容量为10
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
        // 创建一个倒计时锁存器,用于生产者和消费者线程的同步
        CountDownLatch latch = new CountDownLatch(2); // 两个线程
        // 创建一个信号量,用于控制生产者和消费者的并发访问
        Semaphore semaphore = new Semaphore(1, true);

        // 生产者线程
        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    // 生产数据并放入队列
                    queue.put("Product " + (i + 1));
                    // 通知消费者可以消费
                    semaphore.release();
                    // 等待消费者消费
                    semaphore.acquire();
                    // 减少倒计时
                    latch.countDown(); 
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    // 从队列中取出数据
                    String product = queue.take();
                    System.out.println("Consumed: " + product);
                    // 通知生产者可以生产
                    semaphore.release();
                    // 减少倒计时
                    latch.countDown(); 
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 启动生产者和消费者线程
        producer.start();
        consumer.start();

        // 等待倒计时锁存器归零,表示所有线程都已完成它们的任务
        latch.await();

        System.out.println("All tasks completed. Exiting program.");
    }
}

  在这个测试用例中,创建了一个Processor对象,并创建了一个生产者线程和一个消费者线程来测试线程通信的功能。

测试结果

  根据如上测试代码,本地执行结果展示如下:仅供参考

测试代码解析

  如上测试用例演示了一个简单的生产者-消费者问题,使用了ArrayBlockingQueueCountDownLatchSemaphore来进行线程间的通信和同步。以下是对代码的详细分析,希望能够帮助到同学们。

成员变量

  • ArrayBlockingQueue<String> queue: 定义的是一个有界阻塞队列,用于存储字符串类型的数据。队列的容量被初始化为10。当队列为空时,消费者从队列中取出数据会阻塞,而当队列已满时,生产者尝试放入数据也会阻塞。
  • CountDownLatch latch: 定义的是一个倒计时锁存器,用于同步两个线程(生产者和消费者)。它被初始化为2,意味着有两个线程将到达最后的latch.countDown()调用。
  • Semaphore semaphore: 这是一个信号量,用于控制生产者和消费者对共享资源(队列)的访问。它被初始化为1,表示同时只允许一个线程访问队列。

线程定义

  • Thread producer: 生产者线程,定义它的意义在于负责生成数据并将其放入队列。它循环5次,每次生成一个数据项,并通过queue.put()方法放入队列。然后,它释放一个信号量,允许消费者进行消费,并等待消费者完成消费后再继续生产。
  • Thread consumer: 消费者线程,负责从队列中取出数据并消费。它在一个无限循环中,通过queue.take()方法从队列中取出数据,并打印消费信息。消费完成后,它释放一个信号量,允许生产者生成新的数据。

线程启动和同步

  • 两个线程producerconsumer被启动后,将并发执行。
  • latch.await()使主线程等待,直到latch的计数器归零。这意味着主线程将等待生产者和消费者线程完成它们的任务。

异常处理

  在生产者和消费者的循环中,InterruptedException被捕获并处理。如果线程在等待或阻塞操作中被中断,异常将被抛出,并打印堆栈跟踪。

程序结束

  当latch.await()返回时,意味着所有线程都已完成它们的任务。此时,主线程打印一条消息并退出程序。

潜在问题

  其实上述测试用例呢,写的不够严谨,希望同学们只是单纯看着演示即可,实际上是需要留意的,这里我主要是为了演示,就没有写的够严谨,有兴趣的同学可以自行去修缮下。

  • 消费者线程是一个无限循环,它将永远运行,直到程序被外部停止。在实际应用中,你需要一种方法来优雅地关闭消费者线程。
  • 生产者线程在生成5个产品后结束,但消费者线程将继续运行。你可能需要一个条件或信号来控制消费者线程的生命周期。

测试小结

  测试代码主要是给大家演示如何使用Java并发工具来解决生产者-消费者问题;通过使用阻塞队列、倒计时锁存器和信号量,程序实现了线程间的同步和通信。然而,为了使程序在实际应用中更加健壮和灵活,需要进一步考虑线程的生命周期管理和退出条件。

全文小结

  本文以Java开发语言为例,内容上主要介绍了线程通信的概念、应用场景、源代码解析、优缺点分析以及类代码方法。通过学习和了解线程通信的相关知识,可以帮助开发者更好地设计和实现多线程并发程序。

总结

  线程通信是多线程编程中一个重要的概念,通过线程通信可以实现线程之间的协调与合作。Java提供了几种机制来实现线程通信,其中最常用的是使用共享对象的wait、notify和notifyAll方法。在使用线程通信时需要注意相关的并发问题,并进行适当的同步和锁定操作。

… …

  ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看专栏的导读篇《「滚雪球学Java」教程导航帖》,每天学习一小节,日积月累下去,你一定能成为别人眼中的大佬的!功不唐捐,久久为功!

「赠人玫瑰,手留余香」,咱们下期拜拜~~

附录源码

  如上涉及所有源码均已上传同步在「Gitee」,提供给同学们一对一参考学习,辅助你更迅速的掌握。

☀️建议/推荐你

  无论你是计算机专业的学生,还是对编程感兴趣的跨专业小白,都建议直接入手「滚雪球学Java」专栏;该专栏不仅免费,bug菌还郑重承诺,只要你学习此专栏,均能入门并理解Java SE,以全网最快速掌握Java语言,每章节源码均同步「Gitee」,你真值得拥有;学习就像滚雪球一样,越滚越大,带你指数级提升。

码字不易,如果这篇文章对你有所帮助,帮忙给bugj菌来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。

同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 20w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

泰迪智能科技携手广西科技大学理学院共建“上进双创工作室”

6月12日&#xff0c;广东泰迪智能科技股份有限公司携手广西科技大学理学院在泰迪智能科技产教融合实训中心举行“上进双创工作室”签约揭牌仪式&#xff0c;标志“泰迪科技广西科大上进双创工作室”的正式启动。 仪式由泰迪智能科技运营中心总监翁梦婷主持。广西科技大学理学院…

组件二次封装,通过属性事件透传,插槽使用,组件实例方法的绑定,深入理解 Vue.js 组件扩展与插槽

透传&#xff0c;插槽&#xff0c;组件实例方法的绑定&#xff0c;深入理解 Vue.js 组件扩展与插槽 前言 Vue.js 提供了强大的组件化系统&#xff0c;允许开发者构建可复用、可组合的UI组件。在实际项目中&#xff0c;直接使用第三方库提供的基础组件&#xff08;如Element UI…

如何筑牢防线,抵御.anony勒索病毒攻击?

引言 近年来&#xff0c;随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。其中&#xff0c;勒索病毒作为一种新型的网络威胁&#xff0c;给企业和个人用户带来了极大的困扰。在众多勒索病毒中&#xff0c;.anony勒索病毒以其独特的加密方式和勒索手段&#xff0c;引…

2024/6/11 英语每日一段

They found that, regardless of culture, greater mental well-being is linked with feeling emotions that we believe are appropriate to our situation, rather than just having positive emotions regardless of context--“feeling right” as opposed to “feeling g…

深度学习500问——Chapter10:迁移学习(3)

文章目录 11.3 迁移学习的常用方法 11.3.1 数据分布自适应 11.3.2 边缘分布自适应 11.3.3 条件分布自适应 11.3.4 联合分布自适应 11.3.5 概率分布自适应方法优劣性比较 11.3.6 特征选择 11.3.7 统计特征对齐方法 11.3 迁移学习的常用方法 11.3.1 数据分布自适应 数据分布自适…

【配置教程】Linux在企业端为何如此重要

目录 本节重点 先见一下什么是Linux 后台vs前台 企业为何选择使用Linux作为后台服务器 国内企业后台和用户使用Linux现状 1. IT服务器Linux系统应用领域 2. 嵌入式Linux系统应用领域 3. 个人桌面应用领域 Linux时代发展 版本更新 ​编辑 就个人找工作/能力提升来说…

sklearn深度学习指南:掌握机器学习的利器

sklearn深度学习指南&#xff1a;掌握机器学习的利器&#xff01; 1. 简介1.1 什么是sklearn&#xff1f;1.2 sklearn的优势和应用领域1.3 为什么要学习和使用sklearn&#xff1f; 2. 安装和环境设置2.1 如何安装sklearn&#xff1f;安装Anaconda&#xff08;Windows/macOS/Lin…

利用泽攸科技原位TEM技术揭示真空击穿过程中电场与电极材料相互作用

在高能物理设备和许多其他设备中&#xff0c;真空击穿&#xff08;VBD&#xff09;现象对高能物理设备的性能造成了严重的阻碍&#xff0c;包括真空断路器、X射线源、聚变反应堆以及粒子加速器等。然而由于对导致VBD的机制缺乏足够的科学理解&#xff0c;这些问题至今无法得到缓…

618哪些数码产品比较好?2024超高人气产品推荐!

随着6.18大促的脚步渐近&#xff0c;你是否已经按捺不住内心的激动&#xff0c;想要在网络购物的海洋中畅游&#xff0c;尽情享受购物的狂欢&#xff1f;然而&#xff0c;面对繁多的商品和各式各样的优惠活动&#xff0c;你是否感到了一丝迷茫&#xff1f;作为一位经验丰富的网…

一带一路情 相逢《中国缘》-诗琳探访湘西墨戎苗寨交流有感

一带一路情 相逢《中国缘》 诗琳探访湘西墨戎苗寨交流有感 5月21日至25日&#xff0c;《中国缘》栏目组组织的走进湘西苗疆边陲的文化交流活动&#xff0c;在群山环抱、绿树成荫、人文厚重的湘西古丈墨戎苗寨美丽绽放。这场以民间角度推演的中国和中亚人民的文化交流活动&am…

沉降观测点的定义、重要性、建设与选择

沉降观测点&#xff0c;简称沉降点&#xff0c;是指在建筑物、构筑物或地基等结构物上设置的用于测量其垂直位移(沉降)的特定位置。这些点通常被标记并安装相应的监测设备&#xff0c;以便长期、连续地监测结构物的沉降情况。 点击输入图片描述&#xff08;最多30字&#xff09…

Kong AI Gateway 正式 GA !

Kong Gateway 3.7 版本已经重磅上线&#xff0c;我们给 AI Gateway 带来了一系列升级&#xff0c;下面是 AI Gateway 的更新亮点一览。 AI Gateway 正式 GA 在 Kong Gateway 的最新版本 3.7 中&#xff0c;我们正式宣布 Kong AI Gateway 达到了通用可用性&#xff08;GA&…

MySQL 5.7详细下载安装配置教程(MySQL 5.7安装包)_mysql5.7的安装教程

记录MySQL 5.7 的下载安装教程&#xff0c;并提供了Mysql 安装包 &#xff0c;以下是详细下载安装过程。 一、下载Mysql安装包 网盘下载&#xff1a; 下载MySQL 5.7安装包&#xff0c;网盘下载地址&#xff1a;点击此处直接下载 官网下载&#xff1a; 进入官网&#xff0c…

云消息队列 ApsaraMQ 成本治理实践(文末附好礼)

作者&#xff1a;家泽、稚柳 前言&#xff1a; 在 AI 原生应用架构浪潮中&#xff0c;消息队列需支持大规模数据和复杂 AI 模型训练与推理场景下的高效异步通信&#xff0c;其成本效益优化也日益受到重视。面对大模型或大数据量&#xff0c;消息量显著增加&#xff0c;云消息…

利用python爬虫采集苹果公司各产品销售收入统计报告

数据为2013年到2022年苹果公司各产品&#xff08;iPhone、iPad、Mac等&#xff09;及服务的销售收入。iPhone是苹果公司销售收入最高的产品。 数据统计单位为&#xff1a;亿美元 。 数据说明&#xff1a; 数据整理自苹果公司历年10-K文件&#xff0c;每年10-K文件可能对之前年…

构建企业核心竞争力:拥有自主大模型,引领行业未来

前言 随着人工智能技术的飞速发展&#xff0c;大模型技术已经成为推动行业进步的重要力量。在这个变革的时代&#xff0c;作为一位具有前瞻性的企业家&#xff0c;您深知拥有自主大模型对于提升公司竞争力、引领行业未来的重要性。本文将为您详细介绍大模型的市场现状以及企业…

SpringBoot的Mybatis-plus实战之基础知识

文章目录 MybatisPlus 介绍一、MyBatisPlus 集成步骤第一步、引入依赖第二步、定义mapper 二、注解TableNameTableldTableField 三、配置文件四、加解密实现步骤 在SpringBoot项目中使用Mybatis-plus&#xff0c;记录下来&#xff0c;方便备查。 MybatisPlus 介绍 为简化开发而…

亚信科技&用友,助力四川腾翔打通数据壁垒,跑出转型加速度

近日&#xff0c;亚信科技携手用友依托“AntDBU8C”联合产品&#xff0c;助力四川腾翔人力资源管理有限公司&#xff08;以下简称&#xff1a;腾翔&#xff09;打通“人力资源”与“财务”两大业务系统&#xff0c;实现高水平的数据互通、共享和应用&#xff0c;助力业务降本增…

【python】 pandas.DataFrame.to_json 函数

【python】 pandas.DataFrame.to_json 函数 写在最前面一、什么是 JSON&#xff1f;【性能对比】python读取json和直接从orcle数据库读&#xff0c;哪个更快&#xff1f;性能对比适用场景综合考虑 二、to_json 函数概述参数详解1. path_or_buf2. orient4. double_precision5. f…

基于开源模型搭建Agent系统教程

一篇非常基础非常基础的Agent博客 大型语言模型&#xff08;LLMs&#xff09;经过causal language modeling训练后&#xff0c;可以处理各种任务&#xff0c;但它们通常在逻辑、计算和搜索等基本任务上表现不佳。最糟糕的情况是&#xff0c;它们在某个领域&#xff08;如数学&…