生产者消费者模型丐中丐实现!!!
目录
引言
在面试中,多线程编程愈发常见,生产者-消费者模型是一种经典的线程通信模式,广泛应用于任务调度、消息处理、异步执行等场景。本文将通过一段实战代码示例,深入剖析如何使用 Java 的并发工具构建一个高并发安全、结构清晰的任务调度框架。
本文将围绕以下核心问题展开:
- 如何控制生产和消费的节奏?
 - 如何保证任务数量不多不少、恰好执行完?
 - 如何优雅处理线程终止问题?
 - 如何进一步优化提升系统吞吐量?
 
代码结构总览
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Main {
    private static final int QUEUE_SIZE = 12;
    private static final int NUM_PRODUCER = 10;
    private static final int NUM_CONSUMER = 8;
    private static final int NUM_TASK = 100;
    private static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(QUEUE_SIZE);
    private static AtomicInteger count1 = new AtomicInteger(0);
    private static AtomicInteger count2 = new AtomicInteger(0);
    public static void main(String[] args) {
        Thread[] producers = new Thread[NUM_PRODUCER];
        Thread[] consumers = new Thread[NUM_CONSUMER];
        for (int i = 0; i < NUM_PRODUCER; i++) {
            producers[i] = new Thread(new Producer(i));
            producers[i].start();
        }
        for (int i = 0; i < NUM_CONSUMER; i++) {
            consumers[i] = new Thread(new Consumer(i));
            consumers[i].start();
        }
        try {
            for (Thread p : producers) p.join();
            for (Thread c : consumers) c.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ALL TASK HAS DONE.");
    }
    static class Producer implements Runnable {
        final int id;
        public Producer(int id) {
            this.id = id;
        }
        public void run() {
            while (true) {
                if (count1.get() >= NUM_TASK) break;
                try {
                    int curId = count1.incrementAndGet();
                    queue.put(curId);
                    System.out.println("P " + id + " HAS PRODUCED TASK " + curId);
                    Thread.sleep((int) (Math.random() * 2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static class Consumer implements Runnable {
        final int id;
        public Consumer(int id) {
            this.id = id;
        }
        public void run() {
            while (true) {
                if (count2.get() >= NUM_TASK) break;
                try {
                    Integer curId = queue.poll();
                    if (curId == null) {
                        Thread.sleep(10);
                        continue;
                    }
                    count2.incrementAndGet();
                    System.out.println("C " + id + " HAS CON           SUMED TASK " + curId);
                    Thread.sleep((int) (Math.random() * 2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
这段代码实现了一个典型的生产者消费者模型:
- 队列容量: 12
 - 生产者线程数: 10 个
 - 消费者线程数: 8 个
 - 总任务数: 100 个
 
关键成员包括:
BlockingQueue<Integer> queue:用于存储任务的共享队列;AtomicInteger count1, count2:分别用于统计已生产与已消费的任务数,保证线程安全;Producer和Consumer实现了Runnable接口,分别处理任务的生成与消费。
核心代码讲解
共享资源
    private static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(QUEUE_SIZE);
    private static AtomicInteger count1 = new AtomicInteger(0);
    private static AtomicInteger count2 = new AtomicInteger(0);
使用 LinkedBlockingQueue 实现线程安全的任务传递;
AtomicInteger 替代 synchronized,保证原子性并避免锁竞争。
生产者逻辑
    while (true) {
        if (count1.get() >= NUM_TASK) break;
        try {
            int curId = count1.incrementAndGet();
            queue.put(curId);
            System.out.println("P " + id + " HAS PRODUCED TASK " + curId);
            Thread.sleep((int) (Math.random() * 2000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
每个生产者线程不断尝试生成任务,直到总任务数达到上限。
queue.put(curId) 为阻塞操作,当队列满时自动等待。
注意
使用 incrementAndGet() 而非 getAndIncrement() 是为了防止出现越界任务。
任务编号可能不连续(由于并发 + 条件判断的竞态),但总量可控。
消费者逻辑
    while (true) {
        if (count2.get() >= NUM_TASK) break;
        try {
            Integer curId = queue.poll();
            if (curId == null) {
                Thread.sleep(10);
                continue;
            }
            count2.incrementAndGet();
            System.out.println("C " + id + " HAS CONSUMED TASK " + curId);
            Thread.sleep((int) (Math.random() * 2000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
消费者采用 poll() 非阻塞拉取,空则等待一段时间重试,确保所有消费者线程不阻塞;
成功获取任务后,立即执行并统计。
                    
                
                
            
        
浙公网安备 33010602011771号