Java高频面试之并发编程-07

hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶

面试官:线程之间有哪些通信方式?

在 Java 多线程编程中,线程间通信(Inter-Thread Communication)的核心目的是协调不同线程的执行顺序或共享数据。以下是线程间通信的常见方式及其实现原理和应用场景:


1. 共享内存 + 同步机制

原理 :线程通过共享变量(如对象、集合)交换数据,通过锁(synchronizedLock)或原子类(AtomicInteger 等)保证线程安全。
示例

java 复制代码
// 共享变量
private int sharedValue = 0;
private final Object lock = new Object();

// 线程 A 写入
synchronized (lock) {
    sharedValue = 42;
    lock.notifyAll(); // 通知等待的线程
}

// 线程 B 读取
synchronized (lock) {
    while (sharedValue == 0) {
        lock.wait(); // 等待通知
    }
    System.out.println(sharedValue);
}

适用场景:简单的数据共享,需手动处理同步和竞态条件。


2. 阻塞队列(BlockingQueue)

原理 :线程通过线程安全的队列传递数据,生产者写入队列,消费者从队列读取。队列满或空时自动阻塞。
示例

java 复制代码
BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);

// 生产者线程
queue.put("data"); // 队列满时阻塞

// 消费者线程
String data = queue.take(); // 队列空时阻塞

适用场景:生产者-消费者模型,解耦生产与消费逻辑。


3. wait() / notify() / notifyAll()

原理 :基于对象监视器(Monitor)的等待-通知机制,需在 synchronized 块中使用。
示例

java 复制代码
public class TaskCoordinator {
    private boolean isReady = false;

    public void waitForReady() throws InterruptedException {
        synchronized (this) {
            while (!isReady) {
                this.wait(); // 释放锁并等待
            }
        }
    }

    public void setReady() {
        synchronized (this) {
            isReady = true;
            this.notifyAll(); // 唤醒所有等待线程
        }
    }
}

适用场景:线程间的条件协作(如任务启动前的等待)。


4. 同步工具类(Semaphore、CountDownLatch 等)

原理 :通过计数器或状态控制线程的执行流程。
常用类

  • CountDownLatch :等待多个线程完成初始化。

    java 复制代码
    CountDownLatch latch = new CountDownLatch(3);
    
    // 工作线程
    latch.countDown(); // 计数器减 1
    
    // 主线程
    latch.await(); // 等待计数器归零
  • CyclicBarrier :多线程相互等待至屏障点。

    java 复制代码
    CyclicBarrier barrier = new CyclicBarrier(3);
    
    // 每个线程执行到屏障点后等待
    barrier.await();
  • Semaphore :控制并发线程数量。

    java 复制代码
    Semaphore semaphore = new Semaphore(5);
    
    semaphore.acquire(); // 获取许可(无可用许可时阻塞)
    semaphore.release(); // 释放许可

适用场景:复杂线程协作(如分批任务、资源池管理)。


5. 管道(PipedInputStream / PipedOutputStream)

原理 :通过管道流直接传递字节数据,需成对使用。
示例

java 复制代码
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos); // 连接输入输出流

// 生产者线程写入数据
pos.write("data".getBytes());

// 消费者线程读取数据
int data = pis.read();

适用场景:线程间直接传输字节数据(较少使用,性能较低)。


6. Future 和 Callable

原理 :通过 Future 获取另一个线程的异步执行结果。
示例

java 复制代码
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
    Thread.sleep(1000);
    return 42;
});

// 阻塞等待结果
int result = future.get();

适用场景:异步任务执行与结果获取。


7. 事件驱动(如 EventBus)

原理 :基于发布-订阅模式,线程通过事件总线传递消息。
示例(使用 Guava EventBus)

java 复制代码
EventBus eventBus = new EventBus();

// 订阅者
class Subscriber {
    @Subscribe
    public void handleEvent(String event) {
        System.out.println("Received: " + event);
    }
}

eventBus.register(new Subscriber());

// 发布者线程
eventBus.post("Hello");

适用场景:松耦合的事件通知(如 GUI 事件处理)。


8. 回调(Callback)

原理 :线程 A 调用线程 B 的方法时传入回调函数,线程 B 完成任务后调用回调函数通知线程 A。
示例

java 复制代码
interface Callback {
    void onComplete(String result);
}

class Worker {
    void doWork(Callback callback) {
        new Thread(() -> {
            String result = "Done";
            callback.onComplete(result);
        }).start();
    }
}

// 调用
new Worker().doWork(result -> System.out.println(result));

适用场景:异步任务完成后的通知。


对比与选型建议

通信方式 优点 缺点 适用场景
共享内存 + 同步 简单直接 需手动处理同步,易出错 简单数据共享
阻塞队列 线程安全,解耦生产消费 队列容量需合理设置 生产者-消费者模型
wait/notify 灵活的条件控制 需搭配 synchronized 使用 线程条件协作
同步工具类 简化复杂协作逻辑 需理解不同工具的特性 多线程分阶段协作
Future/Callable 支持异步结果获取 仅适用于单次任务 异步任务执行
事件驱动 松耦合,易扩展 依赖第三方库(如 EventBus) 事件通知场景
回调 灵活定制逻辑 回调嵌套可能导致"回调地狱" 异步任务完成通知

注意事项

  1. 线程安全:共享变量必须通过锁或原子类确保可见性和原子性。
  2. 死锁预防:避免嵌套锁和循环等待资源。
  3. 性能权衡 :高并发场景优先选择无锁或细粒度锁(如 ConcurrentHashMap)。
  4. 资源释放 :确保 wait() 后能正常唤醒,避免线程永久阻塞。
相关推荐
好吃的肘子14 分钟前
MongoDB 应用实战
大数据·开发语言·数据库·算法·mongodb·全文检索
ghost14316 分钟前
C#学习第23天:面向对象设计模式
开发语言·学习·设计模式·c#
小白学大数据17 分钟前
Scrapy框架下地图爬虫的进度监控与优化策略
开发语言·爬虫·python·scrapy·数据分析
立秋678923 分钟前
用Python绘制梦幻星空
开发语言·python·pygame
可乐加.糖25 分钟前
项目版本管理和Git分支管理方案
java·git·目标跟踪·gitlab·敏捷流程·源代码管理
独行soc40 分钟前
2025年渗透测试面试题总结-阿里云[实习]阿里云安全-安全工程师(题目+回答)
linux·经验分享·安全·阿里云·面试·职场和发展·云计算
明月看潮生43 分钟前
青少年编程与数学 02-019 Rust 编程基础 16课题、包、单元包及模块
开发语言·青少年编程·rust·编程与数学
wowocpp44 分钟前
spring boot Controller 和 RestController 的区别
java·spring boot·后端
后青春期的诗go1 小时前
基于Rust语言的Rocket框架和Sqlx库开发WebAPI项目记录(二)
开发语言·后端·rust·rocket框架
草莓熊Lotso1 小时前
【C语言字符函数和字符串函数(一)】--字符分类函数,字符转换函数,strlen,strcpy,strcat函数的使用和模拟实现
c语言·开发语言·经验分享·笔记·其他