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

发布于:2024-07-03 ⋅ 阅读:(12) ⋅ 点赞:(0)

在 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. 使用 Lock 和 Condition

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. Lock 和 Condition:提供了更灵活和细粒度的控制,通过显式的锁和条件对象进行线程同步。
  3. BlockingQueue:内置的线程安全队列,实现了生产者-消费者模式,简化了线程间的通信和同步。

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