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

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

方法一:使用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
相关推荐
郭京京12 小时前
goweb模板语法html/template
后端·go
乐神嘎嘎嘎12 小时前
接口测试面试题
后端
七夜zippoe13 小时前
缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(二)
java·开发语言·缓存
AAA修煤气灶刘哥13 小时前
ES数据同步大乱斗:同步双写 vs MQ异步,谁才是王者?
分布式·后端·elasticsearch
毕设源码-邱学长13 小时前
【开题答辩全过程】以 博物馆参观预约管理系统为例,包含答辩的问题和答案
java·eclipse
2301_7816686113 小时前
微服务面试篇
微服务·面试·架构
郭庆汝13 小时前
Windows安装java流程
java·windows·android studio
Yvonne爱编码13 小时前
后端编程开发路径:从入门到精通的系统性探索
java·前端·后端·python·sql·go
迦蓝叶14 小时前
JAiRouter 0.8.0 发布:Docker 全自动化交付 + 多架构镜像,一键上线不是梦
java·人工智能·网关·docker·ai·架构·自动化
im_AMBER14 小时前
Leetcode 18 java
java·算法·leetcode