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

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

方法一:使用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
相关推荐
952362 分钟前
SpringAOP
java·后端·学习·spring
生物信息与育种14 分钟前
黄三文院士领衔植物星球计划(PLANeT)发表Cell
人工智能·深度学习·算法·面试·transformer
浩冉学编程14 分钟前
微信小程序中基于java后端实现官方的文本内容安全识别msgSecCheck
java·前端·安全·微信小程序·小程序·微信公众平台·内容安全审核
A__tao21 分钟前
JSON 转 Java 实体类工具(支持嵌套与注释解析)
java·python·json
zx28596340023 分钟前
Laravel6.x新特性全解析
java·后端·spring
极光代码工作室26 分钟前
基于SpringBoot的图书管理系统
java·springboot·web开发·后端开发
许彰午29 分钟前
# 从OOM到根治的完整过程——导出大数据的应急、根因分析与游标方案
java·大数据·数据库·系统架构
上弦月-编程44 分钟前
C语言指针超详细教程——从入门到精通(面向初学者)
java·数据结构·算法
闵孚龙44 分钟前
一篇文章彻底吃透NumPy与Pandas——从零基础到面试通关的完整指南
面试·numpy·pandas
ANnianStriver1 小时前
Java中的stream流的用法
java