• 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();
        }
    
    千里之行,积于跬步;万里之船,成于罗盘,共勉。
  • 相关阅读:
    PL/SQL集合(一):记录类型(TYPE 类型名称 IS RECORD)
    PL/SQL编程基础(五):异常处理(EXCEPTION)
    PL/SQL编程基础(四):程序控制(IF,CASE,FOR,LOOP,WHILE LOOP,EXIT,CONTINUE)
    PL/SQL编程基础(三):数据类型划分
    PL/SQL编程基础(二):变量的声明、赋值、(赋值、连接、关系、逻辑)运算符
    PL/SQL编程基础(一):PL/SQL语法简介(匿名PL/SQL块)
    SQL Fundamentals || DCL(Data Control Language) || 角色ROLES
    SQL Fundamentals || DCL(Data Control Language) || 系统权限&对象权限管理(GRANT&REVOKE)
    SQL Fundamentals || DCL(Data Control Language) || 用户管理&Profile概要文件
    Oracle Schema Objects——PARTITION
  • 原文地址:https://www.cnblogs.com/Kelin-/p/9475917.html
Copyright © 2020-2023  润新知