你好,我是吴计可师,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。
文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读
线程间通信是指多个线程之间如何交换数据、通知彼此的执行状态以及协调工作。线程间通信在并发编程中是一个重要的概念,它可以让多个线程共同工作,协调资源的访问,避免竞态条件和死锁。
最简单的线程通信方式是通过共享内存(共享变量)来传递数据。多个线程可以访问同一个变量,通过读取和修改共享的变量来交换信息。常见的做法是通过同步来避免并发访问带来的数据不一致性。
Object 类提供了 wait() 和 notify() 方法,这两个方法是线程间通信的基础。wait() 用于让当前线程等待,直到其他线程调用 notify() 或 notifyAll() 来唤醒它。notify() 用于唤醒一个正在等待该对象锁的线程,notifyAll() 用于唤醒所有等待该对象锁的线程。一个常见的例子是生产者和消费者问题,生产者将数据放入缓冲区,消费者从缓冲区取出数据。如果缓冲区为空,消费者需要等待;如果缓冲区满,生产者需要等待。
class SharedBuffer {private int data = -1;private boolean available = false;public synchronized void produce(int value) throws InterruptedException {while (available) {wait(); // 如果有数据,生产者等待}data = value;available = true;System.out.println("Produced: " + value);notify(); // 唤醒消费者}public synchronized int consume() throws InterruptedException {while (!available) {wait(); // 如果没有数据,消费者等待}available = false;System.out.println("Consumed: " + data);notify(); // 唤醒生产者return data;}}class Producer extends Thread {private SharedBuffer buffer;public Producer(SharedBuffer buffer) {this.buffer = buffer;}public void run() {try {for (int i = 1; i <= 5; i++) {buffer.produce(i);Thread.sleep(500);}} catch (InterruptedException e) {e.printStackTrace();}}}class Consumer extends Thread {private SharedBuffer buffer;public Consumer(SharedBuffer buffer) {this.buffer = buffer;}public void run() {try {for (int i = 1; i <= 5; i++) {buffer.consume();Thread.sleep(1000);}} catch (InterruptedException e) {e.printStackTrace();}}}public class ThreadCommunicationExample {public static void main(String[] args) {SharedBuffer buffer = new SharedBuffer();Producer producer = new Producer(buffer);Consumer consumer = new Consumer(buffer);producer.start();consumer.start();}}
在这个例子中,生产者和消费者通过 wait() 和 notify() 方法进行同步。生产者在生产时,如果数据已经存在,它会调用 wait() 使自己进入等待状态,直到消费者消费掉数据并唤醒它;消费者在消费时,如果没有数据,它会调用 wait(),直到生产者生产数据并唤醒它。
BlockingQueue 是 Java 提供的一种线程安全的队列,常用于生产者-消费者模型中。它实现了阻塞和非阻塞方法,线程在从空队列中取数据时会被阻塞,直到队列中有数据;线程在向满队列中放数据时,也会被阻塞,直到队列有空间。常见的实现类有 ArrayBlockingQueue 和 LinkedBlockingQueue。
ExecutorService 是 Java 并发包中用于管理线程池的类,它可以通过 Future 对象来实现线程间的通信,Future 允许线程间共享计算结果。ExecutorService 和 Future 进行线程间通信import java.util.concurrent.*;class Task implements Callable<Integer> {public Integer call() throws Exception {System.out.println("Task started");Thread.sleep(2000); // 模拟耗时操作return 42;}}public class ThreadCommunicationExecutorExample {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<Integer> future = executor.submit(new Task());// 在此可以做其他工作System.out.println("Doing other work...");// 获取结果,阻塞直到任务完成Integer result = future.get();System.out.println("Task result: " + result);executor.shutdown();}}
在这个例子中,Future 提供了 get() 方法来获取异步任务的结果,get() 方法会阻塞,直到任务完成并返回结果。
在多线程环境中,线程往往需要协调工作,避免冲突,同时保证共享资源的正确访问。
在这个例子中,Future 提供了 get() 方法来获取异步任务的结果,get() 方法会阻塞,直到任务完成并返回结果。
一个线程需要等待另一个线程完成某项工作,才能继续执行。
生产者-消费者问题等需要线程之间的协调。
wait() / notify() / notifyAll():这些方法是 Object 类的一部分,可以用于线程间的通信和同步。
BlockingQueue:如 ArrayBlockingQueue, LinkedBlockingQueue 等,这些是线程安全的队列,用于生产者-消费者模式。
CountDownLatch:用于等待某些线程完成后再继续执行。
CyclicBarrier:用于让一组线程等待彼此完成某项工作后再继续执行。
Semaphore:用于控制同时访问某些资源的线程数量。
Exchanger:允许两个线程交换对象。
CountDownLatch:它用于使一个或多个线程等待其他线程完成某项操作后再继续执行。适用于一次性的等待场景,比如等待多个线程执行完毕。它是不可重用的。
示例:等待所有线程执行完毕后,主线程再执行。
CyclicBarrier:它也用于让多个线程在某个点上同步,并在所有线程到达该点后一起继续执行。与 CountDownLatch 不同,CyclicBarrier 是可重用的,适合循环使用。
Exchanger 是一个用于线程间数据交换的同步工具类,它允许两个线程交换数据。每个线程提供一个数据对象,并在交换时交换这些对象。
import java.util.concurrent.*;class ExchangeTask implements Runnable {private final Exchanger<String> exchanger;public ExchangeTask(Exchanger<String> exchanger) {this.exchanger = exchanger;}@Overridepublic void run() {try {String data = "Data from " + Thread.currentThread().getName();String received = exchanger.exchange(data); // 与另一个线程交换数据System.out.println(Thread.currentThread().getName() + " received: " + received);} catch (InterruptedException e) {e.printStackTrace();}}}public class ExchangerExample {public static void main(String[] args) {Exchanger<String> exchanger = new Exchanger<>();Thread thread1 = new Thread(new ExchangeTask(exchanger));Thread thread2 = new Thread(new ExchangeTask(exchanger));thread1.start();thread2.start();}}
今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!