Java 中线程之间如何进行通信?

Sherwin.Wei Lv7

Java 中线程之间如何进行通信?

回答重点

在 Java 中,线程之间的通信是指多个线程协同工作,主要实现方式包括:

1)共享变量

  • 线程可以通过访问共享内存变量来交换信息(需要注意同步问题,防止数据竞争和不一致)。
  • 共享的也可以是文件,例如写入同一个文件来进行通信。

2)同步机制

  • synchronized:Java 中的同步关键字,用于确保同一时刻只有一个线程可以访问共享资源,利用 Object 类提供的 wait()notify()notifyAll()实现线程之间的等待/通知机制
  • ReentrantLock:配合 Condition 提供了类似于 wait()、notify() 的等待/通知机制
  • BlockingQueue:通过阻塞队列实现生产者-消费者模式
  • CountDownLatch:可以允许一个或多个线程等待,直到在其他线程中执行的一组操作完成
  • CyclicBarrier:可以让一组线程互相等待,直到到达某个公共屏障点
  • Volatile:Java 中的关键字,确保变量的可见性,防止指令重排
  • Semaphore:信号量,可以控制对特定资源的访问线程数

补充 Object 中的方法说明:

  • wait():使线程进入等待状态,释放锁。
  • notify():唤醒单个等待线程。
  • notifyAll():唤醒所有等待线程。

扩展知识

wait/notify 机制的详细解读

wait() 会让线程进入阻塞状态,直到调用 notify()notifyAll() 方法,通常结合 synchronized 使用,确保线程获取对象锁后再调用。

例如在经典的生产者-消费者模式中,生产者线程生产数据,如果缓冲区满了,则调用 wait(),等待消费者消费数据后再继续;消费者线程则通过 notify() 唤醒生产者。

示例代码:

1
2
3
4
5
6
7
synchronized (lock) {
while (conditionNotMet) {
lock.wait(); // 释放锁,进入等待状态
}
// 执行操作
lock.notify(); // 唤醒等待的线程
}

Lock 和 Condition

ReentrantLock 提供了更灵活的锁机制,可以中断等待锁的线程,或进行尝试获取锁的操作。

Condition 对象类似于 wait()notify() 的功能,但一个 Lock 可以创建多个 Condition,从而支持多个条件队列。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
while (conditionNotMet) {
condition.await(); // 等待
}
// 执行操作
condition.signal(); // 唤醒等待的线程
} finally {
lock.unlock();
}

BlockingQueue

BlockingQueue 是线程安全的阻塞队列,广泛应用于生产者-消费者模型。生产者通过 put() 方法将元素放入队列,如果队列满了,生产者线程会被阻塞;消费者通过 take() 方法从队列中取元素,如果队列为空,消费者线程会被阻塞。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);

// 生产者
new Thread(() -> {
try {
queue.put("Data");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();

// 消费者
new Thread(() -> {
try {
String data = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
Comments