Java 多线程通信方式及实现方法

在 Java 多线程编程中,线程之间的通信是实现协作和同步的关键。以下是常见的线程通信方式及其实现方法:

1. 共享变量 + `wait()` / `notify()` / `notifyAll()`

这是基于 `Object` 类的经典线程通信机制,需配合 `synchronized` 同步块使用。

适用场景

生产者 - 消费者模型、线程协作任务。

示例

java
public class SharedResource {
    private int value;
    private boolean isEmpty = true;

    public synchronized void produce(int newValue) throws InterruptedException {
        while (!isEmpty) {
            wait(); // 等待消费者消费
        }
        value = newValue;
        isEmpty = false;
        notifyAll(); // 通知消费者可以消费
    }

    public synchronized int consume() throws InterruptedException {
        while (isEmpty) {
            wait(); // 等待生产者生产
        }
        isEmpty = true;
        notifyAll(); // 通知生产者可以生产
        return value;
    }
}

 特点

  * `wait()` 释放锁并让线程进入等待状态。
  * `notify()` 唤醒一个等待线程,`notifyAll()` 唤醒所有等待线程。
  * 必须用 `while` 循环检查条件,防止 **虚假唤醒**(spurious wakeup)。

 2. `Lock` 和 `Condition`(显式锁)

Java 5 引入的 `java.util.concurrent.locks` 包提供了更灵活的锁机制,支持多个条件变量。

适用场景

复杂条件协作(如多生产者 - 多消费者)。

示例

java
import java.util.concurrent.locks.*;

public class SharedResourceWithLock {
    private final Lock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();
    private int value;
    private boolean isEmpty = true;

    public void produce(int newValue) throws InterruptedException {
        lock.lock();
        try {
            while (!isEmpty) {
                notFull.await(); // 等待队列非满
            }
            value = newValue;
            isEmpty = false;
            notEmpty.signal(); // 通知队列非空
        } finally {
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty) {
                notEmpty.await(); // 等待队列非空
            }
            isEmpty = true;
            notFull.signal(); // 通知队列非满
            return value;
        } finally {
            lock.unlock();
        }
    }
}
 特点

  * 可以创建多个 `Condition` 对象,精确控制线程的等待和唤醒。
  * 支持公平锁、非公平锁,以及 `tryLock()` 等灵活操作。

3. 阻塞队列(`BlockingQueue`)

`java.util.concurrent.BlockingQueue` 提供了线程安全的队列操作,天然支持线程通信。

适用场景

生产者 - 消费者模型的简化实现。

示例

java
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueDemo {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

        // 生产者
        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    queue.put(i); // 队列满时自动阻塞
                    System.out.println("Produced: " + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 消费者
        new Thread(() -> {
            try {
                while (true) {
                    int value = queue.take(); // 队列空时自动阻塞
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

特点

  * `put()` 和 `take()` 方法自动阻塞,简化线程同步。
  * 支持有界队列和无界队列(如 `LinkedBlockingQueue`)。

4. 共享变量 + `volatile`

通过 `volatile` 关键字保证变量的内存可见性,实现简单状态标记。

 适用场景

简单的线程状态控制(如终止线程)。

示例

java
public class VolatileDemo {
    private volatile boolean running = true;

    public void stop() {
        running = false;
    }

    public void runTask() {
        new Thread(() -> {
            while (running) {
                // 执行任务
            }
            System.out.println("线程终止");
        }).start();
    }
}

特点

  * `volatile` 保证变量的修改对其他线程立即可见。
  * **不能保证复合操作的原子性**(如 `i++`)。

5. 管道通信(`PipedInputStream` / `PipedOutputStream`)

通过管道流实现线程间数据传输。

示例

java
import java.io.*;

public class PipedCommunication {
    public static void main(String[] args) throws IOException {
        final PipedOutputStream output = new PipedOutputStream();
        final PipedInputStream input = new PipedInputStream(output);

        // 生产者线程
        new Thread(() -> {
            try {
                output.write("Hello from producer!".getBytes());
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            try {
                int data;
                while ((data = input.read()) != -1) {
                    System.out.print((char) data);
                }
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

特点

  * 适合线程间直接传输字节流或字符流。
  * 实际开发中使用较少,通常用更高级的队列代替。

6. 同步工具类(`CountDownLatch`, `CyclicBarrier`, `Semaphore`)

Java 并发包中的工具类支持更复杂的线程协作。

示例(CountDownLatch)

java
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println("子线程执行任务");
                latch.countDown(); // 计数器减1
            }).start();
        }

        latch.await(); // 等待所有子线程完成
        System.out.println("所有子线程执行完毕");
    }
}

特点

  * `CountDownLatch`:一次性使用,等待多个线程完成。
  * `CyclicBarrier`:可重复使用,多个线程互相等待到屏障点。
  * `Semaphore`:控制同时访问资源的线程数。

总结

  * **简单协作**:优先使用 `BlockingQueue` 或 `volatile`。
  * **复杂条件**:用 `Lock` + `Condition` 或 `synchronized` + `wait()/notify()`。
  * **数据传输**:选择 `BlockingQueue` 或管道流。
  * **线程同步工具**:合理使用 `CountDownLatch`、`CyclicBarrier` 等。

**注意**:避免死锁(确保锁的获取顺序一致)、竞态条件(正确同步共享资源)和过度同步(影响性能)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值