Java如何在两个线程之间共享数据?

本文探讨了Java中多线程通信的共享内存方式,强调了可见性、有序性和原子性的重要性。通过JMM解决可见性和有序性问题,锁解决原子性问题。介绍了将数据操作封装为类的方法和使用内部类的Runnable对象实现数据操作同步的策略。

Java 里面进行多线程通信的主要方式就是共享内存的方式,共享内存主要的关注点有两个:可见性和有序性原子性。Java
内存模型(JMM)解决了可见性和有序性的问题,而锁解决了原子性的问题,理想情况下我们希望做到“同步”和“互斥”。

有以下常规实现方法:

  1. 将数据抽象成一个类,并将对这个数据的操作作为这个类的方法,这么设计可以和容易做到同步,只要在方法上加”synchronized“

  2. 将Runnable对象作为一个类的内部类,共享数据作为这个类的成员变量,每个线程对共享数据的操作方法也封装在外部类,以便实现对数据的各个操作的同步和互斥,作为内部类的各个 Runnable 对象调用外部类的这些方法。

Java 中,**线程之间的通信**主要是通过共享内存和线程协作机制实现的。常见的线程通信方式包括: --- ### 一、通过共享对象(共享变量) 多个线程访问同一个对象的字段,通过读写该字段进行通信。通常配合 `synchronized`、`volatile` 或 `java.util.concurrent` 包中的类使用。 - **volatile**:确保变量的可见性。 - **synchronized**:确保变量的原子性和可见性。 示例: ```java public class SharedObject { private volatile boolean flag = false; public void setFlag() { flag = true; } public boolean getFlag() { return flag; } } ``` 线程 A 修改 `flag`,线程 B 读取它,从而实现通信。 --- ### 二、使用 `wait()`、`notify()` 和 `notifyAll()` 这些方法定义在 `Object` 类中,用于线程间的协调通信。 - `wait()`:当前线程等待,直到其他线程调用 `notify()` 或 `notifyAll()`。 - `notify()`:唤醒一个等待的线程。 - `notifyAll()`:唤醒所有等待的线程。 使用时必须在 `synchronized` 块或方法中。 示例: ```java public class ProducerConsumer { private int data; private boolean flag = false; public synchronized void produce() throws InterruptedException { while (flag) { wait(); // 等待消费者消费 } data = (int)(Math.random() * 100); System.out.println("Produced: " + data); flag = true; notify(); // 通知消费者 } public synchronized void consume() throws InterruptedException { while (!flag) { wait(); // 等待生产者生产 } System.out.println("Consumed: " + data); flag = false; notify(); // 通知生产者 } } ``` --- ### 三、使用 `BlockingQueue`(阻塞队列) `java.util.concurrent` 包中的 `BlockingQueue` 是线程安全的队列,常用于生产者-消费者模型。 - `put()`:如果队列满则阻塞。 - `take()`:如果队列空则阻塞。 示例: ```java BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5); // 生产者线程 new Thread(() -> { try { for (int i = 0; ; i++) { queue.put(i); System.out.println("Produced: " + i); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); // 消费者线程 new Thread(() -> { try { while (true) { int value = queue.take(); System.out.println("Consumed: " + value); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); ``` --- ### 四、使用 `CountDownLatch`、`CyclicBarrier`、`Phaser` 这些类用于线程之间的同步和协作: - **CountDownLatch**:一个线程等待多个线程完成。 - **CyclicBarrier**:多个线程相互等待,到达屏障后一起继续执行。 - **Phaser**:更灵活的同步工具,支持动态注册线程。 --- ### 五、使用 `Exchanger` `Exchanger` 是一个用于两个线程之间交换数据的同步点。 示例: ```java Exchanger<String> exchanger = new Exchanger<>(); new Thread(() -> { try { String data = "Data from Thread 1"; String received = exchanger.exchange(data); System.out.println("Thread 1 received: " + received); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); new Thread(() -> { try { String data = "Data from Thread 2"; String received = exchanger.exchange(data); System.out.println("Thread 2 received: " + received); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); ``` --- ### 总结 | 通信方式 | 适用场景 | 是否需要同步 | |----------------------|----------------------------------|---------------| | 共享变量 + volatile | 简单状态通知 | 是 | | wait/notify | 线程间协作 | 是 | | BlockingQueue | 生产者-消费者模型 | 否(线程安全)| | CountDownLatch | 一个线程等待多个线程 | 否 | | CyclicBarrier | 多个线程相互等待 | 否 | | Exchanger | 两个线程交换数据 | 否 | ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值