并发-常见笔试题-生产者消费者

基于多线程编程实现一个生产者消费者模型

方法一:使用Object的wait和notify

代码如下

java 复制代码
private static Object object = new Object();
private static int SIZE = 10;
private static LinkedList<Integer> list = new LinkedList<>();
private static volatile boolean flag = true;

@Test
public void testCase01() {
    ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {
        private volatile int index = 0;

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "t" + (index++));
        }
    });

    for (int i = 0; i < 5; i++) {
        threadPool.submit(new Producer());
        threadPool.submit(new Consumer());
    }

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    threadPool.shutdown();


}

private static class Producer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            synchronized (object) {
                if (list.size() >= SIZE) {
                    object.notifyAll();
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is full " +
                            " size=" + list.size());
                } else {
                    int num = new Random().nextInt(100);
                    list.addLast(num);
                    System.out.println(Thread.currentThread().getName() + " add num=" + num +
                            " size=" + list.size());
                    object.notifyAll();
                }


            }
        }
    }
}

private static class Consumer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            synchronized (object) {
                if (list.size() <= 0) {
                    object.notifyAll();
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is full " +
                            " size=" + list.size());
                } else {
                    int num = list.removeFirst();
                    System.out.println(Thread.currentThread().getName() + " remove num=" + num +
                            " size=" + list.size());
                    object.notifyAll();
                }
            }
        }
    }
}

运行结果

ini 复制代码
t6 add num=9 size=1
t2 add num=2 size=2
t0 add num=31 size=3
t3 remove num=9 size=2
t1 remove num=2 size=1
t7 remove num=31 size=0
t4 add num=13 size=1
t8 add num=9 size=2

方法2:基于阻塞队列实现

代码实现

java 复制代码
private static int SIZE = 2;
private static BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>(SIZE);
private static volatile boolean flag = true;
private static AtomicInteger curSize = new AtomicInteger(0);

@Test
public void testCase01() {
    ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {
        private volatile int index = 0;

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "t" + (index++));
        }
    });

    for (int i = 0; i < 5; i++) {
        threadPool.submit(new Producer());
        threadPool.submit(new Consumer());
    }

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    threadPool.shutdown();


}

private static class Producer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));

            int num = new Random().nextInt(100);
            try {
                blockingDeque.put(num);
                System.out.println(Thread.currentThread().getName() + " add num=" + num +
                        " size=" + curSize.addAndGet(1));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

private static class Consumer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            try {
                int num = blockingDeque.take();
                System.out.println(Thread.currentThread().getName() + " remove num=" + num +
                        " size=" + curSize.addAndGet(-1));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

打印结果

打印结果因为多线程导致是乱序的

ini 复制代码
t8 add num=24 size=1
t3 remove num=70 size=0
t7 remove num=76 size=1
t0 add num=70 size=2
t4 add num=76 size=1
t5 remove num=70 size=0

方法3:使用Lock和Condition实现

代码实现

java 复制代码
private static ReentrantLock lock = new ReentrantLock();
private static Condition notEmpty = lock.newCondition();
private static Condition notFull = lock.newCondition();
private static int SIZE = 10;
private static LinkedList<Integer> list = new LinkedList<>();
private static volatile boolean flag = true;

@Test
public void testCase01() {
    ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {
        private volatile int index = 0;

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "t" + (index++));
        }
    });

    for (int i = 0; i < 5; i++) {
        threadPool.submit(new Producer());
        threadPool.submit(new Consumer());
    }

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    threadPool.shutdown();


}

private static class Producer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            lock.lock();
            try {


                if (list.size() >= SIZE) {
                    notEmpty.signalAll();
                    try {
                        notFull.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is full " +
                            " size=" + list.size());
                } else {
                    int num = new Random().nextInt(100);
                    list.addLast(num);
                    System.out.println(Thread.currentThread().getName() + " add num=" + num +
                            " size=" + list.size());
                    notEmpty.signalAll();
                }
            } finally {
                lock.unlock();
            }

        }
    }
}

private static class Consumer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            lock.lock();
            if (list.size() <= 0) {
                notFull.signalAll();
                try {
                    notEmpty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " is full " +
                        " size=" + list.size());
            } else {
                int num = list.removeFirst();
                System.out.println(Thread.currentThread().getName() + " remove num=" + num +
                        " size=" + list.size());
                notFull.signalAll();
            }
        }
    }
}

执行结果

实现方式和wait和notify一样

ini 复制代码
t8 add num=70 size=1
t6 add num=4 size=2
t0 add num=17 size=3
t4 add num=22 size=4
t7 remove num=70 size=3
t7 remove num=4 size=2

方法4:使用信号量来实现

实现代码

java 复制代码
private static int SIZE = 10;
private static Semaphore notEmpty = new Semaphore(0);
private static Semaphore notFull = new Semaphore(SIZE);
private static LinkedList<Integer> list = new LinkedList<>();
private static volatile boolean flag = true;
private static AtomicInteger curSize = new AtomicInteger(0);

@Test
public void testCase01() {
    ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {
        private volatile int index = 0;

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "t" + (index++));
        }
    });

    for (int i = 0; i < 5; i++) {
        threadPool.submit(new Producer());
        threadPool.submit(new Consumer());
    }

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    threadPool.shutdown();


}

private static class Producer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            try {
                notFull.acquire();
                int num = new Random().nextInt(100);
                list.addLast(num);
                System.out.println(Thread.currentThread().getName() + " add num=" + num +
                        " size=" + curSize.addAndGet(1));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                notEmpty.release();
            }
        }
    }
}

private static class Consumer implements Runnable {
    @Override
    public void run() {
        while (flag) {
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(200));
            try {
                notEmpty.acquire();
                int num = list.removeFirst();
                System.out.println(Thread.currentThread().getName() + " remove num=" + num +
                        " size=" + curSize.addAndGet(-1));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                notFull.release();
            }

        }
    }
}

执行结果

执行结果会乱序

ini 复制代码
t0 add num=60 size=1
t8 add num=79 size=2
t6 add num=58 size=4
t4 add num=56 size=3
t2 add num=49 size=4
t7 remove num=60 size=3
t1 remove num=58 size=0
t5 remove num=56 size=1
相关推荐
数智启示录21 分钟前
Flink CDC 机制精讲(二):Checkpoint Barrier 如何形成一致快照 【面试宝典】
大数据·经验分享·面试·flink
MC皮蛋侠客22 分钟前
Tauri 2.x 系列(五):调用系统 API——官方插件、Rust crate 与原生能力
开发语言·后端·rust
许彰午2 小时前
13-describe元数据输出
java·低代码·架构·状态模式
Profile排查笔记2 小时前
指纹浏览器怎么设置 IP?代理配置、检测与排错流程
前端·人工智能·后端·自动化
用户3721574261353 小时前
Java 设置 Word 文档编辑限制并允许指定区域编辑
java
宠友信息3 小时前
社区类源码开发实践中的仿小红书系统技术要点分析
java·spring boot·redis·mysql·uni-app·vue·内容运营
IT_陈寒3 小时前
SpringBoot自动配置失效?你可能漏了这个小开关
前端·人工智能·后端
用户3721574261353 小时前
Java 设置 PDF 表单域只读或扁平化
java
摇滚侠4 小时前
《SpringBoot 3:入门与应用实战》第 9 章 使用 WebMvc 开发应用 阅读笔记 1
spring boot·笔记·后端
用户8356290780514 小时前
使用 Python 在 Excel 中插入 OLE 对象
后端·python