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

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

方法一:使用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
相关推荐
小灰灰__17 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
马剑威(威哥爱编程)20 分钟前
MongoDB面试专题33道解析
数据库·mongodb·面试
夜雨翦春韭20 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果41 分钟前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林1 小时前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
duration~2 小时前
Maven随笔
java·maven
zmgst2 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD2 小时前
前后端分离,Jackson,Long精度丢失
java