详细说明线程间如何进行通信。

参考回答

线程间通信可以通过多种方式实现,最常见的是使用共享对象等待/通知机制,比如通过 wait()notify()notifyAll() 方法进行协调。此外,还可以使用更高级的工具,比如 java.util.concurrent 包中的类,如 CountDownLatchCyclicBarrierSemaphoreBlockingQueue

一个简单的例子是使用共享对象作为锁,在线程之间共享数据并通过 wait()notify() 进行通信。


详细讲解与拓展

线程间通信的核心在于线程协作,通常需要解决以下两个问题:

  1. 如何共享数据:多个线程之间需要有共同的操作对象。
  2. 如何协调执行顺序:线程之间需要知道何时进行操作或等待。

方法一:使用 wait()notify()

wait()notify()Object 类的方法,必须在同步块中调用,否则会抛出 IllegalMonitorStateException。这些方法可以通过共享对象来协调线程间的通信。

代码示例:生产者-消费者模型

class SharedResource {
    private int data;
    private boolean isProduced = false;

    public synchronized void produce(int value) throws InterruptedException {
        while (isProduced) {
            wait(); // 等待消费者消费
        }
        data = value;
        System.out.println("Produced: " + data);
        isProduced = true;
        notify(); // 通知消费者可以消费了
    }

    public synchronized int consume() throws InterruptedException {
        while (!isProduced) {
            wait(); // 等待生产者生产
        }
        System.out.println("Consumed: " + data);
        isProduced = false;
        notify(); // 通知生产者可以生产了
        return data;
    }
}

public class ThreadCommunication {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    resource.produce(i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    resource.consume();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

关键点解释:

  • wait():使当前线程等待,直到被其他线程通过 notify() 唤醒。
  • notify():唤醒一个正在等待的线程。
  • notifyAll():唤醒所有正在等待的线程。

方法二:使用 java.util.concurrent 包中的工具类

为了简化线程间通信,Java 提供了许多并发工具类。

使用 BlockingQueue

BlockingQueue 是线程安全的队列,可以用来实现生产者-消费者模型,避免手动处理同步问题。

代码示例:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueExample {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);

        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    queue.put(i); // 队列满时自动阻塞
                    System.out.println("Produced: " + i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    int value = queue.take(); // 队列为空时自动阻塞
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

优点:

  • BlockingQueue 自动处理了线程同步问题。
  • 简化了代码逻辑。

方法三:使用 CountDownLatch

CountDownLatch 用于一个或多个线程等待其他线程完成某些操作。

代码示例:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        Runnable task = () -> {
            System.out.println(Thread.currentThread().getName() + " completed task");
            latch.countDown(); // 每完成一个任务,计数减1
        };

        new Thread(task).start();
        new Thread(task).start();
        new Thread(task).start();

        latch.await(); // 等待所有任务完成
        System.out.println("All tasks are completed!");
    }
}

关键点解释:

  • countDown():将计数器减1。
  • await():主线程阻塞,直到计数器为0。

拓展知识

  1. 线程安全性:线程间通信时需要注意共享资源的安全性,常用方法是加锁或使用并发工具类。

  2. ReentrantLock 的条件变量:相比 synchronized,ReentrantLock提供了更灵活的线程通信方式,通过 Condition实现等待/通知机制。

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    
  3. CompletableFuture:适用于异步任务之间的通信,可以简化复杂的线程间依赖。

发表评论

后才能评论