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() 后能正常唤醒,避免线程永久阻塞。
相关推荐
二哈赛车手2 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
为何创造硅基生物3 小时前
C语言 结构体内存对齐规则(通俗易懂版)
c语言·开发语言
吃好睡好便好3 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
栗子~~3 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
星寂樱易李3 小时前
iperf3 + Python-- 网络带宽、网速、网络稳定性
开发语言·网络·python
YDS8293 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
仰泳之鹅3 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
之歆3 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜4 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
未若君雅裁4 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis