JAVA实现生产消费者模型

前言

最近面试比较多,发现生产消费者模型在各公司面试的过程中问的还是比较多的,记录一下常见JAVA实现生产者消费模型的代码

思路

我们通过三种模式来实现

  1. 通过wait和notify
  2. 通过Lock和Condition
  3. 通过JAVA内部的阻塞队列ArrayBlockingQueue

代码

  1. wait和notify

通过synchronized来保证线程安全,在消息满或者不足的时候wait进行阻塞,然后notifyAll来通知其他监听

static class Storage {

        private Queue<Integer> queue;

        private Integer max;


        public Storage(Queue<Integer> queue, Integer max) {
            this.queue = queue;
            this.max = max;
        }

        private synchronized void produce(Integer msg) {

            while (queue.size() > max) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.offer(msg);
            this.notifyAll();
        }

        private synchronized Integer consume() {

            while (queue.size() == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Integer result = queue.poll();
            this.notifyAll();
            return result;
        }
    }
  1. Lock和Condition

通过Lock来保证线程安全,通过Condition来实现阻塞和通信,在消息队列满的时候,通过notFull的wait和notEmpty的signalAll来阻塞当前生产者并且通知消费者来消费消息,消息队列空的时候同理

 static class Storage {

        private Queue<Integer> queue;

        private Integer max;

        private Lock lock;

        private Condition notEmpty;

        private Condition notFull;


        public Storage(Queue<Integer> queue, Integer max) {
            this.queue = queue;
            this.max = max;
            lock = new ReentrantLock();
            notEmpty = lock.newCondition();
            notFull = lock.newCondition();
        }

        private void produce(Integer msg) {

            lock.lock();
            try {
                while (queue.size() > max) {
                    notFull.await();
                }
                queue.offer(msg);
                notEmpty.signalAll();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }

        private synchronized Integer consume() {
            lock.lock();
            Integer result = null;
            try {
                while (queue.size() == 0) {
                    notEmpty.await();
                }
                result = queue.poll();
                notFull.signalAll();
            } catch (Exception e) {
                e.printStackTrace();

            } finally {
                lock.unlock();
            }
            return result;
        }
    }
  1. 通过JAVA的实现类ArrayBlockingQueue

ArrayBlockingQueue是一个阻塞队列,在队列满的时候put会阻塞,空的时候take也会阻塞,其内部实现也是基于Lock和Condition来实现的

 static class Storage {

        private ArrayBlockingQueue<Integer> queue;


        public Storage(Integer max) {
            this.queue = new ArrayBlockingQueue<>(max);
        }

        private void produce(Integer msg) {
            try {
                queue.put(msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        private Integer consume() {
            try {
                return queue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

测试

生产线程:

 static class Producer implements Runnable {

        private Storage storage;

        private Integer msg;

        public Producer(Storage storage, Integer msg) {
            this.storage = storage;
            this.msg = msg;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                storage.produce(msg);
                System.out.println("this is producer :" + msg);
            }
        }
    }

消费者线程:

 static class Consumer implements Runnable {

        private Storage storage;

        public Consumer(Storage storage) {
            this.storage = storage;
        }

        @Override
        public void run() {

            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this is consumer:" + storage.consume());
            }
        }
    }

测试用例:通过多个生产者消费者线程来模拟,执行代码后可验证生产和消费的有序进行

 public static void main(String[] args) {


        Storage storage = new Storage(2);

        Producer producer = new Producer(storage, 1);
        Producer producer2 = new Producer(storage, 2);
        Producer producer3 = new Producer(storage, 3);

        new Thread(producer).start();
        new Thread(producer2).start();
        new Thread(producer3).start();


        Consumer consumer1 = new Consumer(storage);
        Consumer consumer2 = new Consumer(storage);
        Consumer consumer3 = new Consumer(storage);

        new Thread(consumer1).start();
        new Thread(consumer2).start();
        new Thread(consumer3).start();
    }
posted @ 2018-08-14 17:18  __Kelin  阅读(146)  评论(0编辑  收藏  举报