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

在 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:内置的线程安全队列,实现了生产者-消费者模式,简化了线程间的通信和同步。

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

相关推荐
sycmancia几秒前
Qt——Qt中的标准对话框
开发语言·qt
aq55356003 分钟前
四大编程语言对比:PHP、Python、Java、易语言
java·python·php
橙露17 分钟前
Python 对接 API:自动化拉取、清洗、入库一站式教程
开发语言·python·自动化
Omigeq23 分钟前
1.4 - 曲线生成轨迹优化算法(以BSpline和ReedsShepp为例) - Python运动规划库教程(Python Motion Planning)
开发语言·人工智能·python·算法·机器人
2301_8084143825 分钟前
自动化测试的实施
开发语言·python
波波00742 分钟前
写出稳定C#系统的关键:不可变性思想解析
开发语言·c#·wpf
成为大佬先秃头43 分钟前
前后分离项目:整合JWT+Shiro
java·springboot·shiro·jwt
y = xⁿ1 小时前
【Leet Code 】滑动窗口
java·算法·leetcode
day day day ...1 小时前
MyBatis条件误写引发的查询条件污染分析与防范
java·服务器·tomcat
dr_yingli1 小时前
fMRI(3-1)报告(个体化报告)生成器说明
开发语言·matlab