Java中的线程通信的几种方式

news2024/11/24 11:27:32

Java中的线程间通信是指不同线程之间相互协作,以完成一些复杂的任务或实现某些功能的过程。线程间通信主要包括两个方面:线程之间的互斥和同步,以及线程之间的数据共享和通信。Java提供了多种方式来实现线程间通信,本文将介绍Java中的几种常见的线程间通信方式。

在这里插入图片描述

synchronized关键字

synchronized是Java中最基本的实现线程之间互斥和同步的机制。synchronized可以用来修饰方法或代码块,用来确保在同一时间只有一个线程可以执行被修饰的代码块或方法。通过synchronized关键字,我们可以实现线程之间的互斥和同步。以下是一个使用synchronized实现线程同步的例子:

public class SynchronizedDemo {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

在这个例子中,我们使用synchronized关键字修饰了increment()和getCount()方法,以确保在同一时间只有一个线程可以执行这两个方法。这样就可以避免不同线程之间对count变量的并发访问和修改,从而实现线程之间的同步和互斥。

wait()和notify()方法

wait()和notify()方法是Java中实现线程间通信的另一种方式。wait()方法可以使线程进入等待状态,直到其他线程调用notify()方法来通知该线程继续执行。notify()方法可以唤醒一个正在等待的线程,使其继续执行。以下是一个使用wait()和notify()方法实现线程通信的例子:

public class WaitNotifyDemo {
    public static void main(String[] args) {
        Message message = new Message("Hello World");

        // 创建发送线程
        Thread senderThread = new Thread(new Sender(message));
        // 创建接收线程
        Thread receiverThread = new Thread(new Receiver(message));

        // 启动发送线程和接收线程
        senderThread.start();
        receiverThread.start();
    }
}

class Message {
    private String content;

    public Message(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

class Sender implements Runnable {
    private Message message;

    public Sender(Message message) {
        this.message = message;
    }

    public void run() {
        String[] messages = {"message1", "message2", "message3"};

        for (String message : messages) {
            // 发送消息
            this.message.setContent(message);

            try {
                // 等待接收线程接收消息
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Receiver implements Runnable {
    private Message message;

    public Receiver(Message message) {
        this.message = message;
    }

    public void run() {
        for (int i = 0; i < 3; i++) {
            // 等待发送线程发送消息
            synchronized (message) {
                try {
                    message.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 接收并处理消息
            System.out.println("Received message: " + message.getContent());
        }
    }
}

在这个例子中,我们使用wait()和notify()方法来实现线程间的通信。Sender线程通过设置message对象的content属性来发送消息,然后等待1秒钟,让Receiver线程有足够的时间来接收消息。Receiver线程通过wait()方法来等待Sender线程发送消息,直到接收到消息后再进行处理。

CountDownLatch类

CountDownLatch类是Java中提供的一种线程同步工具,它可以用来控制一个或多个线程等待其他线程完成任务后再继续执行。CountDownLatch类的工作原理是通过一个计数器来实现的,当计数器的值减为0时,等待该计数器的线程将被唤醒。以下是一个使用CountDownLatch类实现线程同步的例子:

public class CountDownLatchDemo {
    public static void main(String[] args) {
        final int N = 3;
        final CountDownLatch latch = new CountDownLatch(N);

        // 创建N个线程
        for (int i = 0; i < N; i++) {
            new Thread() {
                public void run() {
                    try {
                        // 线程执行任务
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println(Thread.currentThread().getName() + " completed task");

                        // 计数器减1
                        latch.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

        try {
            // 等待所有线程完成任务
            latch.await();
            System.out.println("All threads completed their tasks.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,我们使用CountDownLatch类来实现线程之间的同步。我们创建了N个线程,并让它们执行任务,每个线程执行任务后都会将计数器减1,直到所有线程都执行完任务后,主线程才会继续执行。

Semaphore类

Semaphore类是Java中提供的一种线程同步工具,它可以用来控制同时访问某个资源的线程数量。Semaphore类的工作原理是通过一个计数器来实现的,当每个线程访问该资源时,计数器就减1,当计数器的值为0时,其他线程就不能再访问该资源。以下是一个使用Semaphore类实现线程间通信的例子:

public class SemaphoreDemo {
    public static void main(String[] args) {
        final int N = 10;
        final Semaphore semaphore = new Semaphore(3);

        // 创建N个线程
        for (int i = 0; i < N; i++) {
            new Thread() {
                public void run() {
                    try {
                        // 请求许可证
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + " acquired permit");

                        // 线程执行任务
                        Thread.sleep((long) (Math.random() * 10000));

                        // 释放许可证
                        semaphore.release();
                        System.out.println(Thread.currentThread().getName() + " released permit");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
}

在这个例子中,我们使用Semaphore类来控制同时访问某个资源的线程数量。我们创建了N个线程,并让它们请求许可证,如果许可证的数量已经达到了3个,那么其他线程就需要等待,直到有线程释放许可证后才能继续执行。

BlockingQueue类

BlockingQueue类是Java中提供的一种线程安全的队列,它可以用来实现线程间的数据共享和通信。BlockingQueue类的工作原理是,当队列为空时,从队列中取数据的操作会被阻塞,直到队列中有数据;当队列已满时,向队列中添加数据的操作会被阻塞,直到队列中有空间。以下是一个使用BlockingQueue类实现线程间通信的例子:

public class BlockingQueueDemo {
    public static void main(String[] args) {
        final int N = 10;
        final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(N);

        // 创建发送线程
        Thread senderThread = new Thread(new Sender(queue));
        // 创建接收线程
        Thread receiverThread = new Thread(new Receiver(queue));

        // 启动发送线程和接收线程
        senderThread.start();
        receiverThread.start();
    }
}

class Sender implements Runnable {
    private BlockingQueue<String> queue;

    public Sender(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    public void run() {
        String[] messages = {"message1", "message2", "message3"};

        for (String message : messages){
            try {
                // 添加消息到队列中
                queue.put(message);
                System.out.println("Sent message: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
         }
       }
 }

class Receiver implements Runnable {
    private BlockingQueue<String> queue;
        public Receiver(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    public void run() {
        while (true) {
            try {
                // 从队列中取出消息
                String message = queue.take();
                System.out.println("Received message: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个例子中,我们使用BlockingQueue类来实现线程间的通信。Sender线程通过调用queue.put()方法将消息添加到队列中,Receiver线程通过调用queue.take()方法从队列中取出消息。如果队列为空,Receiver线程会阻塞,直到有消息被添加到队列中。同样地,如果队列已满,Sender线程也会阻塞,直到有空间可用。

总结

Java中提供了多种方式来实现线程间通信,其中最常见的方式包括synchronized关键字、wait()和notify()方法、CountDownLatch类、Semaphore类和BlockingQueue类。这些方式都可以用来实现线程之间的互斥、同步、数据共享和通信。选择哪种方式取决于具体的应用场景和需求。在使用这些方式时,需要注意线程安全和死锁等问题,以确保程序的正确性和健壮性。

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

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

相关文章

Java | 一分钟掌握定时任务 | 5 - Spring Task

作者&#xff1a;Mars酱 声明&#xff1a;本文章由Mars酱原创&#xff0c;部分内容来源于网络&#xff0c;如有疑问请联系本人。 转载&#xff1a;欢迎转载&#xff0c;转载前先请联系我&#xff01; 前言 多线程解决了并发阻塞问题&#xff0c;但是不能方便的表达我们的定时方…

redi可持久化配置

回顾&#xff1a;rpcbind111 nfs2049 redis高可用高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%&#xff0c;99.99%&#xff0c;99.999%等&#xff09; 还要考虑提供主从分离&#xff0c;快速容灾技术&#…

用netty实现聊天

1.引入netty依赖 <dependencies> <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.92.Final</version> </dependency> </dependencies> 2.准备一个服务端ChatServer和…

Redis优化与常见问题

---------------------- Redis 命令工具 ---------------------------------------- redis-server&#xff1a;用于启动 Redis 的工具 redis-benchmark&#xff1a;用于检测 Redis 在本机的运行效率 redis-check-aof&#xff1a;修复 AOF 持久化文件 redis-check-rdb&#xff1…

C语言库函数详解(两万字)

目录 目录 目录 前言 1.C 标准库 - <stdio.h> 简介 1.1 printf&#xff08;&#xff09;&#xff1b; 1.2 scanf(); 1.3 getchar(); 1.4 putchar(); 1.5 gets(); 1.6 puts(); 1.7fscanf(); 1.8 fprintf(); 1.9 fgetc(); 1.10 fgets(); 1.11 fputs(); 1.12 fclose();…

人机融合智能中的诱导引导交互

智能的核心不在于人工智能系统的记忆、注意力和上下文感知等能力&#xff0c;而在于其能够洞察、理解和解决问题的能力。也就是说智能系统需要具备更高层次的思维能力&#xff0c;能够从信息中抽象出本质&#xff0c;识别问题的核心&#xff0c;并提供有效的解决方案。这对于人…

MATLAB绘制动画(四)AVI

MATLAB绘制动画&#xff08;四&#xff09;AVI与GIF clc; clear; close all; fig figure ; aviobj avifile(example.avi); n 100; t 0:2*pi/n:2*pi; x cos(t); y sin(t); for k 1:nx(k) cos(t(k));y(k) sin(t(k));H plot(x,y,x(k),y(k),or,x(k),-y(k),ob);axis equa…

应届生怎么才能提高职场竞争力

前言 随着社会的不断发展&#xff0c;竞争也在逐渐增加。对于应届生来说&#xff0c;提高职场竞争力是很重要的&#xff0c;这样才能更好地融入工作环境、获得更好的机会和待遇。那么&#xff0c;应届生怎么才能提高职场竞争力呢&#xff1f;本文就来简单聊一聊。 应届生步入职…

【再获殊荣】中创算力入选“河南省2023年第五批拟入库科技型中小企业名单”

科技促发展&#xff0c;创新赢未来&#xff01; 科技型中小企业作为最具活力、最具潜力、最具成长性的创新群体&#xff0c;已成为我国在经济转型阶段培育发展新动能的重要载体&#xff01; 2022年&#xff0c;中创算力正式入库河南省2022年科技型中小企业。 2023年&#xf…

F. Array Stabilization (GCD version)

题目链接&#xff1a;传送门 思路&#xff1a; 进行预处理的算法模板&#xff1a; for(int i1;(1<<i)<n;i)for(int j1;j(1<<i)-1<n;j)st[j][i]gcd(st[j][i-1],st[j(1<<(i-1))][i-1]);进行查询的算法模板 int check(int i,int mid){int klog2(mid-i1);…

【Mybatis】Mybatis的动态SQL、缓存机制-三

唠嗑部分 之前我们说了Mybatis的基本操作、关系映射等等&#xff0c;相关文章&#xff1a; 【Mybatis】简单入门及工具类封装-一 【Mybatis】如何实现ORM映射-二 本篇文章和大家说的是Mybatis的动态SQL、缓存机制 言归正传 一、动态SQL MyBatis的映射文件中支持在基础SQL上…

系统分析师:六、企业信息化战略与实施

目录 一、信息与信息化概念 1.1 信息的概念 1.2 信息化的概念 二、信息系统 2.1 信息系统的概念 2.2 信息系统的类型 2.3 信息系统的生命周期 2.4 系统建模 2.5 信息系统战略规划 2.6 信息化开发方法 三、电子政务 四、企业资源计划(ERP) 五、系统集成 一、信息与信息…

k8s1.20版本部署Redis集群(三主三从)——2023.05

文章目录 一、准备工作二、逻辑图三、部署Redis集群1. 安装NFS服务2. 修改API配置3. 创建持久卷PVC4. 创建Redis服务4. 组建Redis集群5. 验证集群 一、准备工作 主机规划 节点IPk8s-master1192.168.2.245k8s-master2192.168.2.246k8s-master3192.168.2.247k8s-node1192.168.2…

【MySQL】-- 库的操作

目录 库的操作 显示数据库 创建数据库 创建数据库案例 删除数据库 删除数据库案例 字符集和校验规则 字符集 校验规则 小结 查看数据库支持的字符集 查看数据库支持的校验规则 校验规则对数据库的影响 不区分大小写 区分大小写 进行查询 结果排序 修改数据库…

我爱我家联合第四范式发布房产经纪大模型

5月15日&#xff0c;在我爱我家年度品牌战略发布会上&#xff0c;我爱我家联合第四范式发布“房产经纪大模型”&#xff0c;将大模型能力用于提升行业生产力的原点&#xff1a;赋能经纪人。本次发布的房产经纪大模型1.0版本已经具备了合格经纪人的基本能力&#xff0c;‍‍‍‍…

leetcode 不同路径详解

文章目录 62 . 不同路径题目详情动态规划之带备忘录实现Java完整代码 63. 不同路径 II题目详情动态规划之带备忘录实现Java完整代码 62 . 不同路径 题目详情 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只…

JavaSE进阶(二)—— 面向对象进阶(包、权限修饰符、抽象类、多态)

目录 一、包 1. 什么是包 2. 导包 二、权限修饰符 1. 什么是权限修饰符 2. 权限修饰符的分类和具体作用范围 3. 学完权限修饰符需要具备如下能力 三、final 1. final的作用 2. final修饰变量的注意 四、常量 1. 常量概述和基本作用 1.1 常量做信息配置的原理、优…

【操作系统】I/O管理

文章目录 I/O设备的基本概念和分类I/O设备的分类 I/O控制器I/O设备的组成I/O控制器的组成I/O控制器的两种寄存器编址方式 I/O控制方式程序直接控制方式中断驱动方式DMA方式通道控制方式 I/O软件的层次结构用户层软件设备独立性软件六大功能逻辑设备表—LUT 设备驱动程序中断处理…

免交互的使用

免交互的使用 一、免交互二、小实验三、利用脚本完成的小实验三、Expect 一、免交互 Here Document 免交互 使用I/O重定向的方式将命令列表提供给交互式程序或命令&#xff0c;比如ftp、cat或者read命令。 免交互时标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来…

MySQL查询练习题

一&#xff0e;编程题 有三张表&#xff0c;结构如下&#xff1a; Student(学号StuId,姓名StuName,性别StuSex,出生年月StuBirth) Course(课程号CouId,课程名CouName,授课教师CoouTeacher) SC(学号StuId,课程号CouId,成绩Score,授课教师CouTeacher) 用标准SQL语句完成下列操作…