两个线程之间是如何通信的呢?

在 Java 中,线程之间的通信(Inter-thread Communication)是指多个线程在程序中共享数据时进行的协作和同步。线程间通信的主要目的是协调线程的工作,确保数据的一致性和正确性,避免竞争条件和死锁。常见的线程通信机制包括 wait() 方法、notify() 方法和 notifyAll() 方法,以及更高级的并发工具类,如 LockConditionBlockingQueue 等。下面详细介绍这些机制和工具。

1. 使用 wait()notify()notifyAll()

这些方法是 Object 类的一部分,用于在同步代码块或方法中实现线程间的等待/通知机制。它们必须在同步代码块或方法中调用。

wait()
  • 使当前线程进入等待状态,直到其他线程调用 notify()notifyAll() 方法唤醒它。
  • 当前线程必须持有对象的监视器锁。
notify()
  • 唤醒一个等待线程。如果有多个线程在等待,则随机选择一个唤醒。
  • 唤醒的线程必须重新获取监视器锁才能继续执行。
notifyAll()
  • 唤醒所有等待线程。唤醒的线程会竞争监视器锁,只有一个线程能获得锁并继续执行。
示例代码
复制代码

java复制代码

class SharedResource { private int value = 0; private boolean available = false; public synchronized void produce(int newValue) throws InterruptedException { while (available) { wait(); } value = newValue; available = true; notify(); } public synchronized int consume() throws InterruptedException { while (!available) { wait(); } available = false; notify(); return value; } } class Producer extends Thread { private SharedResource resource; public Producer(SharedResource resource) { this.resource = resource; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { resource.produce(i); System.out.println("Produced: " + i); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Consumer extends Thread { private SharedResource resource; public Consumer(SharedResource resource) { this.resource = resource; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { int value = resource.consume(); System.out.println("Consumed: " + value); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class WaitNotifyExample { public static void main(String[] args) { SharedResource resource = new SharedResource(); new Producer(resource).start(); new Consumer(resource).start(); } }

2. 使用 LockCondition

java.util.concurrent.locks 包中的 LockCondition 接口提供了更灵活和强大的线程同步机制。与内置的锁和条件相比,LockCondition 提供了更细粒度的控制。

示例代码
复制代码

java复制代码

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; class SharedResource { private int value = 0; private boolean available = false; private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public void produce(int newValue) throws InterruptedException { lock.lock(); try { while (available) { condition.await(); } value = newValue; available = true; condition.signal(); } finally { lock.unlock(); } } public int consume() throws InterruptedException { lock.lock(); try { while (!available) { condition.await(); } available = false; condition.signal(); return value; } finally { lock.unlock(); } } } class Producer extends Thread { private SharedResource resource; public Producer(SharedResource resource) { this.resource = resource; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { resource.produce(i); System.out.println("Produced: " + i); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Consumer extends Thread { private SharedResource resource; public Consumer(SharedResource resource) { this.resource = resource; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { int value = resource.consume(); System.out.println("Consumed: " + value); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class LockConditionExample { public static void main(String[] args) { SharedResource resource = new SharedResource(); new Producer(resource).start(); new Consumer(resource).start(); } }

3. 使用 BlockingQueue

java.util.concurrent 包中的 BlockingQueue 接口提供了一种线程安全的队列实现,支持在队列满时等待生产和在队列空时等待消费。常见的实现类有 ArrayBlockingQueueLinkedBlockingQueue 等。

示例代码
复制代码

java复制代码

import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; class Producer extends Thread { private BlockingQueue<Integer> queue; public Producer(BlockingQueue<Integer> queue) { this.queue = queue; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { queue.put(i); System.out.println("Produced: " + i); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Consumer extends Thread { private BlockingQueue<Integer> queue; public Consumer(BlockingQueue<Integer> queue) { this.queue = queue; } @Override public void run() { try { for (int i = 1; i <= 5; i++) { int value = queue.take(); System.out.println("Consumed: " + value); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5); new Producer(queue).start(); new Consumer(queue).start(); } }

总结

在 Java 中,线程之间的通信可以通过多种机制实现:

  1. wait()notify()notifyAll():基于对象监视器的等待/通知机制,需在同步代码块或方法中使用。
  2. LockCondition:提供了更灵活和细粒度的控制,通过显式的锁和条件对象进行线程同步。
  3. BlockingQueue:内置的线程安全队列,实现了生产者-消费者模式,简化了线程间的通信和同步。

选择合适的线程通信机制可以提高程序的效率和可靠性,并简化并发编程的复杂性。

相关推荐
持梦远方8 分钟前
C 语言基础入门:基本数据类型与运算符详解
c语言·开发语言·c++
一头生产的驴15 分钟前
java整合itext pdf实现自定义PDF文件格式导出
java·spring boot·pdf·itextpdf
YuTaoShao22 分钟前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
zzywxc78725 分钟前
AI 正在深度重构软件开发的底层逻辑和全生命周期,从技术演进、流程重构和未来趋势三个维度进行系统性分析
java·大数据·开发语言·人工智能·spring
灵性花火44 分钟前
Qt的前端和后端过于耦合(0/7)
开发语言·前端·qt
DES 仿真实践家2 小时前
【Day 11-N22】Python类(3)——Python的继承性、多继承、方法重写
开发语言·笔记·python
YuTaoShao3 小时前
【LeetCode 热题 100】56. 合并区间——排序+遍历
java·算法·leetcode·职场和发展
Code Warrior3 小时前
【每日算法】专题五_位运算
开发语言·c++
程序员张33 小时前
SpringBoot计时一次请求耗时
java·spring boot·后端
沐知全栈开发5 小时前
HTML DOM 访问
开发语言