Java 生产者-消费者模式

在 Java 中,生产者-消费者模式(Producer-Consumer Pattern)是一种常见的多线程设计模式,通常用于在多线程环境中协调数据生产和消费,以提高程序的吞吐量,并防止生产过快或消费过快导致数据丢失或资源浪费。

实现方式

1. 使用 synchronized + wait + notify

import java.util.LinkedList;
import java.util.Queue;

class SharedQueue {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 5;

    public synchronized void produce(int value) throws InterruptedException {
        while (queue.size() == capacity) {
            System.out.println("队列已满,生产者等待...");
            wait(); // 释放锁,并等待
        }
        queue.add(value);
        System.out.println("生产:" + value);
        notify(); // 唤醒消费者
    }

    public synchronized int consume() throws InterruptedException {
        while (queue.isEmpty()) {
            System.out.println("队列为空,消费者等待...");
            wait(); // 释放锁,并等待
        }
        int value = queue.poll();
        System.out.println("消费:" + value);
        notify(); // 唤醒生产者
        return value;
    }
}

public class ProducerConsumerSynchronized {
    public static void main(String[] args) {
        SharedQueue sharedQueue = new SharedQueue();

        // 生产者线程
        Thread producer = new Thread(() -> {
            int value = 0;
            try {
                while (true) {
                    sharedQueue.produce(value++);
                    Thread.sleep(500); // 模拟生产耗时
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    sharedQueue.consume();
                    Thread.sleep(1000); // 模拟消费耗时
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.start();
        consumer.start();
    }
}

解释

  • 使用 synchronized 确保线程安全
  • 使用 wait() 让线程在条件不满足时等待(生产者等待队列有空位,消费者等待有数据)。
  • 使用 notify() 唤醒对方线程(生产者唤醒消费者,消费者唤醒生产者)。
  • 生产和消费在不同的线程中进行,互相协调。

2. 使用 BlockingQueue(推荐)

BlockingQueue 是 Java 提供的线程安全队列,自动处理线程等待唤醒,比 synchronized + wait/notify 更简洁。

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

class Producer implements Runnable {
    private final BlockingQueue<Integer> queue;

    public Producer(BlockingQueue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        int value = 0;
        try {
            while (true) {
                queue.put(value);
                System.out.println("生产:" + value);
                value++;
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable {
    private final BlockingQueue<Integer> queue;

    public Consumer(BlockingQueue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                int value = queue.take();
                System.out.println("消费:" + value);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ProducerConsumerBlockingQueue {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
    }
}

解释

  • BlockingQueue 自动管理线程同步,不需要 synchronized
  • put()take() 方法自动阻塞生产者或消费者,避免 wait/notify 处理复杂逻辑。

3. 使用 Lock + Condition

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SharedResource {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 5;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public void produce(int value) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                System.out.println("队列已满,生产者等待...");
                notFull.await();
            }
            queue.add(value);
            System.out.println("生产:" + value);
            notEmpty.signal(); // 唤醒消费者
        } finally {
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                System.out.println("队列为空,消费者等待...");
                notEmpty.await();
            }
            int value = queue.poll();
            System.out.println("消费:" + value);
            notFull.signal(); // 唤醒生产者
            return value;
        } finally {
            lock.unlock();
        }
    }
}

public class ProducerConsumerLock {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread producer = new Thread(() -> {
            int value = 0;
            try {
                while (true) {
                    resource.produce(value++);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                while (true) {
                    resource.consume();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.start();
        consumer.start();
    }
}

解释

  • ReentrantLock 提供更灵活的锁机制
  • Condition 代替 wait/notify,更清晰地控制线程等待和唤醒。

总结

方法 线程安全 代码简洁性 适用场景
synchronized + wait/notify 一般 适用于小规模同步需求
BlockingQueue 最佳 推荐,代码简单、性能高
Lock + Condition 一般 适用于更复杂的同步控制