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交替执行

<think>我们正在讨论Java线程间通信方法。根据引用[1][2][3],线程通信是指多个线程通过共享内存或消息传递等方式协调工作。常见的通信方式包括共享对象、wait/notify机制、Lock/Condition、CountDownLatch等并发工具以及volatile变量等。下面我将详细介绍这些方法。 ### 一、共享对象与synchronized同步 通过共享对象加锁实现线程协调,使用wait()和notify()/notifyAll()方法控制线程执行顺序。引用[2]展示了这种经典方式: ```java // 示例:三个线程按顺序打印A、B、C class NextOpt { private int nextValue = 0; // 0:A, 1:B, 2:C public int getNextValue() { return nextValue; } public void setNextValue(int value) { nextValue = value; } } class ThreadABC extends Thread { private NextOpt opt; private String[] abc = {"A", "B", "C"}; private int index; public ThreadABC(NextOpt opt, int index) { this.opt = opt; this.index = index; } @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (opt) { while (opt.getNextValue() != index) { try { opt.wait(); // 不符合条件则等待 } catch (InterruptedException e) { /*...*/ } } System.out.print(abc[index]); opt.setNextValue((index + 1) % 3); opt.notifyAll(); // 唤醒所有等待线程 } } } } // 使用方式 public static void main(String[] args) { NextOpt opt = new NextOpt(); new ThreadABC(opt, 0).start(); // A new ThreadABC(opt, 1).start(); // B new ThreadABC(opt, 2).start(); // C } ``` **原理**:每个线程在共享对象`opt`上同步,通过`opt.nextValue`判断自己是否该执行。若不该执行则调用`wait()`释放锁并等待;执行后更新状态并调用`notifyAll()`唤醒其他线程[^2]。 ### 二、Lock与Condition `java.util.concurrent.locks.Lock`接口提供的`Condition`对象更灵活,可替代synchronized的wait/notify。示例: ```java import java.util.concurrent.locks.*; class PrintInOrder { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private int state = 0; // 0:A, 1:B, 2:C public void printA() { lock.lock(); try { while (state != 0) condition.await(); System.out.print("A"); state = 1; condition.signalAll(); } finally { lock.unlock(); } } // 类似实现printB(), printC()... } ``` **优势**:一个Lock可创建多个Condition,实现精细控制(如只唤醒特定类型线程)[^1]。 ### 三、并发工具类 1. **CountDownLatch**:主线程等待多个子线程完成任务。 ```java CountDownLatch latch = new CountDownLatch(2); new Thread(() -> { /*任务*/ latch.countDown(); }).start(); new Thread(() -> { /*任务*/ latch.countDown(); }).start(); latch.await(); // 主线程等待直到计数器归零 ``` 2. **CyclicBarrier**:多个线程相互等待,到达屏障点后继续执行。 ```java CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达")); for (int i = 0; i < 3; i++) { new Thread(() -> { // ...工作 barrier.await(); // 等待其他线程 }).start(); } ``` 3. **Semaphore**:控制同时访问资源的线程数。 ```java Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问 semaphore.acquire(); // 获取许可 try { /*访问资源*/ } finally { semaphore.release(); } ``` ### 四、volatile变量 轻量级通信方式,保证变量可见性(但不保证原子性)。适用于状态标志: ```java volatile boolean running = true; new Thread(() -> { while (running) { /*工作*/ } }).start(); // 其他线程可通过running=false停止该线程 ``` ### 五、管道通信(PipedStream) 用于线程间字节流或字符流传递,较少使用: ```java PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); // 线程A写数据到pos // 线程B从pis读数据 ``` ### 总结 Java线程通信的核心目标是协调多线程的执行顺序或状态同步。选择方式时需考虑: - **简单协作**:优先使用`wait/notify`或`Lock/Condition`; - **复杂同步**:使用`CountDownLatch`、`CyclicBarrier`等并发工具; - **状态标志**:用`volatile`变量; - **避免**低效的忙等待(busy-waiting)[^1][^3]。 §§相关问题§§ 1. 如何避免线程通信中的死锁问题? 2. `wait()`和`sleep()`方法有何本质区别? 3. 在分布式系统中如何实现线程(进程)间通信? 4. Java中哪些通信方式适用于高并发场景? [^1]: Java中的线程通信详解。通过以上内容,我们详细介绍了 Java 中的线程通信机制,包括基本概念、常用方法及其具体代码示例,并探讨了使用更高级的并发工具类实现线程通信方法。掌握这些知识,能够帮助我们编写出更加高效和可靠的多线程程序。 [^2]: Java 线程间通信。ThreadABC类 public class ThreadABC extends Thread { ... } [^3]: Java实现线程间通信的五种方式。假设有两个线程:线程A和线程B。两个线程都可以依次打印三个数字(1-3)。让我们看一下代码: private static void demo1() { ... }</think>## Java 线程间通信方法详解 在 Java 多线程编程中,线程间通信是协调多个线程协同工作的关键技术。以下是 Java 线程通信的主要方式及其实现原理: ### 一、共享对象通信(基础方式) 通过共享对象的同步机制实现线程通信,使用 `synchronized` 关键字和 `wait()/notify()` 方法: ```java class SharedResource { private boolean flag = false; public synchronized void produce() { while(flag) { try { wait(); // 等待消费者消费 } catch (InterruptedException e) {} } System.out.println("生产数据"); flag = true; notifyAll(); // 通知消费者 } public synchronized void consume() { while(!flag) { try { wait(); // 等待生产者生产 } catch (InterruptedException e) {} } System.out.println("消费数据"); flag = false; notifyAll(); // 通知生产者 } } ``` **原理**: 1. `wait()`:释放锁并进入等待状态 2. `notify()`:随机唤醒一个等待线程 3. `notifyAll()`:唤醒所有等待线程 4. 必须在同步代码块内使用(`synchronized`)[^2] ### 二、Lock/Condition 机制(更灵活) Java 5+ 提供了更灵活的 `Lock` 和 `Condition` 接口: ```java import java.util.concurrent.locks.*; class SharedResource { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean flag = false; public void produce() { lock.lock(); try { while(flag) { condition.await(); // 等待 } System.out.println("生产数据"); flag = true; condition.signalAll(); // 通知所有等待线程 } finally { lock.unlock(); } } // 类似实现consume方法... } ``` **优势**: - 支持多个条件队列 - 可中断的锁获取 - 公平锁选项 - 更细粒度的控制[^1] ### 三、并发工具类(高级方式) #### 1. CountDownLatch(倒计时门闩) ```java CountDownLatch latch = new CountDownLatch(3); // 初始化计数器 // 工作线程 new Thread(() -> { // 执行任务 latch.countDown(); // 计数器减1 }).start(); // 主线程等待 latch.await(); // 阻塞直到计数器归零 System.out.println("所有任务完成"); ``` #### 2. CyclicBarrier(循环屏障) ```java CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达屏障点")); for (int i = 0; i < 3; i++) { new Thread(() -> { // 执行任务 barrier.await(); // 等待其他线程 }).start(); } ``` #### 3. Semaphore(信号量) ```java Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问 new Thread(() -> { semaphore.acquire(); // 获取许可 try { // 访问共享资源 } finally { semaphore.release(); // 释放许可 } }).start(); ``` ### 四、BlockingQueue(阻塞队列) 实现生产者-消费者模式的优雅方式: ```java BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10); // 生产者 new Thread(() -> { queue.put(1); // 阻塞直到队列有空位 }).start(); // 消费者 new Thread(() -> { int item = queue.take(); // 阻塞直到队列有元素 }).start(); ``` ### 五、volatile 变量(轻量级通信) 保证可见性的轻量级同步: ```java class Shared { private volatile boolean flag = false; public void setFlag() { flag = true; // 对所有线程立即可见 } } ``` **适用场景**:状态标志位,单写多读场景[^1] ### 六、管道通信(PipedStream) ```java PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); // 生产者线程 new Thread(() -> { pos.write("数据".getBytes()); }).start(); // 消费者线程 new Thread(() -> { int data = pis.read(); // 阻塞读取 }).start(); ``` ### 选择指南 | 通信方式 | 适用场景 | 特点 | |-------------------|----------------------------------|--------------------------| | wait/notify | 简单生产者-消费者 | 基础API,需同步块 | | Lock/Condition | 复杂同步需求 | 更灵活,支持多个条件队列 | | BlockingQueue | 生产者-消费者模式 | 线程安全,易用 | | CountDownLatch | 主线程等待多个子线程完成 | 一次性使用 | | CyclicBarrier | 多个线程相互等待 | 可重复使用 | | volatile | 状态标志位 | 轻量级,无原子性保证 | ### 最佳实践 1. 优先使用 `java.util.concurrent` 包中的高级工具 2. 避免使用 `stop()` 和 `suspend()` 等已废弃方法 3. 使用线程池管理线程资源 4. 注意死锁预防(避免嵌套锁、使用超时机制) 5. 同步范围最小化(减少性能影响) ```java // 线程池+BlockingQueue 最佳实践 ExecutorService executor = Executors.newFixedThreadPool(2); BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); executor.submit(() -> { while(true) { Runnable task = queue.take(); // 自动阻塞 task.run(); } }); ``` 掌握这些线程通信技术,可以构建高效可靠的多线程应用[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值