Java 中线程通信方式笔记

发布于:2025-07-13 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

  1. 线程通信的定义
  2. 使用 wait() / notify() 通信
  3. 使用 join() 实现线程串行
  4. 使用 volatile 实现可见性通信
  5. 使用 LockSupport
  6. 使用 Condition
  7. 使用 BlockingQueue
  8. 使用 CountDownLatchCyclicBarrierSemaphore
  9. 使用 Future / CompletableFuture
  10. 总结

1.线程通信的定义

线程通信是指多个线程在协同完成某个任务时,为了数据同步或协作调度而相互传递信息或等待状态变化的机制。

常见目的:

  • 数据共享同步(生产者-消费者)
  • 控制线程顺序(线程 A -> 线程 B)
  • 等待某一条件满足后继续执行

2.使用 wait() / notify() 通信

最基础的通信方式,依赖对象锁和监视器机制。

示例:

class Shared {
    private boolean ready = false;

    public synchronized void waitForSignal() throws InterruptedException {
        while (!ready) {
            wait(); // 释放锁 + 阻塞
        }
        System.out.println("Signal received!");
    }

    public synchronized void sendSignal() {
        ready = true;
        notify(); // 唤醒等待线程
    }
}

特点:

  • 必须配合 synchronized 使用
  • wait() 会释放锁,notify() 不会
  • 建议使用 while 判断条件防止虚假唤醒

3.使用 join() 实现线程串行

等待其他线程执行完成,适合线程之间有执行顺序依赖的场景。

示例:

Thread t1 = new Thread(() -> {
    System.out.println("T1 done");
});
Thread t2 = new Thread(() -> {
    try {
        t1.join();
        System.out.println("T2 done after T1");
    } catch (InterruptedException e) {}
});

t1.start();
t2.start();

4.使用 volatile 实现可见性通信

适用于简单的标志状态共享,如线程停止。

示例:

class Flag {
    volatile boolean stop = false;
}

Flag flag = new Flag();

new Thread(() -> {
    while (!flag.stop) {
        // do work
    }
}).start();

Thread.sleep(1000);
flag.stop = true;

特点:

  • 保证线程间变量的可见性
  • 不保证原子性
  • 适合轻量级信号传递

5.使用 LockSupport

线程阻塞和唤醒的底层工具,替代 wait/notify,无需加锁。

示例:

Thread t = new Thread(() -> {
    System.out.println("Thread park");
    LockSupport.park();
    System.out.println("Thread unparked");
});
t.start();

Thread.sleep(1000);
LockSupport.unpark(t);

特点:

  • 每个线程有一个许可证(类似信号量)
  • 更灵活,不依赖同步锁
  • 常用于实现框架级线程调度

6.使用 Condition

Lock 的增强版 wait/notify,支持多个条件队列。

示例:

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

Thread t1 = new Thread(() -> {
    lock.lock();
    try {
        condition.await(); // 类似 wait()
        System.out.println("Thread t1 resumed");
    } catch (InterruptedException e) {} 
    finally {
        lock.unlock();
    }
});

Thread t2 = new Thread(() -> {
    lock.lock();
    condition.signal(); // 类似 notify()
    lock.unlock();
});

特点:

  • 可精准唤醒特定条件队列中的线程
  • 支持多个等待队列

7.使用 BlockingQueue

适合生产者-消费者模式,线程安全队列内置通信机制。

示例:

BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);

new Thread(() -> {
    try {
        queue.put(1); // 阻塞直到有空间
    } catch (InterruptedException e) {}
}).start();

new Thread(() -> {
    try {
        Integer value = queue.take(); // 阻塞直到有元素
        System.out.println("Consumed: " + value);
    } catch (InterruptedException e) {}
}).start();

8.使用 CountDownLatch/CyclicBarrier/Semaphore

CountDownLatch

用于一个线程等待多个线程完成:

CountDownLatch latch = new CountDownLatch(2);

new Thread(() -> {
    latch.countDown(); // 执行完毕
}).start();

latch.await(); // 等待所有线程执行完

CyclicBarrier

适合多个线程在某个点同步:

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("All threads reached barrier");
});

new Thread(() -> {
    barrier.await();
}).start();

Semaphore

用于控制线程数量(资源数):

Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问

semaphore.acquire();
try {
    // 访问共享资源
} finally {
    semaphore.release();
}

9.使用 Future / CompletableFuture

线程间通过结果对象通信,适合异步执行与回调。

示例:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
    return "result";
});

String result = future.get(); // 阻塞直到任务完成

CompletableFuture

CompletableFuture.supplyAsync(() -> "Hello")
    .thenApply(str -> str + " World")
    .thenAccept(System.out::println);

总结

方式 适用场景 是否阻塞 特点
wait/notify 精细通信 必须配合锁
join 等待线程完成 简单串行依赖
volatile 状态通知 可见性但无原子性
LockSupport 框架底层调度 灵活、无锁
Condition 多条件控制 精细唤醒
BlockingQueue 生产者消费者 内置通信机制
CountDownLatch 等待一组线程 一次性门闩
CyclicBarrier 多线程集结 可重复使用
Semaphore 控制访问数量 控制并发度
Future/CompletableFuture 异步编程 支持回调 返回值通信

网站公告

今日签到

点亮在社区的每一天
去签到