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

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

方法一:使用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
相关推荐
hanqunfeng7 小时前
(三十三)Redisson 实战
java·spring boot·后端
2301_780669867 小时前
字符集及其编码、解码操作、IO流分类
java·开发语言
计算机毕设指导67 小时前
基于微信小程序的运动场馆服务系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
Mr__Miss7 小时前
Redis网络模型
数据库·redis·面试
冰暮流星7 小时前
javascript的switch语句介绍
java·前端·javascript
有梦想的攻城狮7 小时前
Java中的Double类型的存在精度丢失详解
java·开发语言·bigdecimal·double
tod1137 小时前
从零手写一个面试级 C++ vector:内存模型、拷贝语义与扩容策略全解析
c++·面试·职场和发展·stl·vector
m0_748249547 小时前
Java 语言提供了八种基本类型【文123】
java·开发语言·python
移幻漂流8 小时前
Kotlin 如何解决 Java 的核心痛点:现代语言特性的深度剖析
java·python·kotlin
leikooo8 小时前
ShardingSphere 下更新分片键导致的失败问题分析与解决
java·spring·apache