zoukankan      html  css  js  c++  java
  • Java多线程(九):生产者消费者模型

    生产者消费者模型

    生产者:生产任务的个体;
    消费者:消费任务的个体;
    缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦。

    缓冲区元素为满,生产者无法生产,消费者继续消费;
    缓冲区元素为空,消费者无法消费,生产者继续生产;

    wait()/notify()生产者消费者模型

    制作一个简单的缓冲区ValueObject,value为空表示缓冲区为空,value不为空表示缓冲区满

    public class ValueObject {
    
        public static String value = "";
    
    }
    

    生产者,缓冲区满则wait(),不再生产,等待消费者notify(),缓冲区为空则开始生产

    public class Producer {
        private Object lock;
    
        public Producer(Object lock)
        {
            this.lock = lock;
        }
    
        public void setValue()
        {
            try
            {
                synchronized (lock)
                {
                    if (!ValueObject.value.equals(""))
                        lock.wait();
                    String value = System.currentTimeMillis() + "_" + System.nanoTime();
                    System.out.println("Set的值是:" + value);
                    ValueObject.value = value;
                    lock.notify();
                }
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    

    消费者,缓冲区为空则wait(),等待生产者notify(),缓冲区为满,消费者开始消费

    public class Customer {
        private Object lock;
    
        public Customer(Object lock)
        {
            this.lock = lock;
        }
    
        public void getValue()
        {
            try
            {
                synchronized (lock)
                {
                    if (ValueObject.value.equals(""))
                        lock.wait();
                    System.out.println("Get的值是:" + ValueObject.value);
                    ValueObject.value = "";
                    lock.notify();
                }
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    

    main方法,启动一个生产者和一个消费者

    public class Main {
        public static void main(String[] args)
        {
            Object lock = new Object();
            final Producer producer = new Producer(lock);
            final Customer customer = new Customer(lock);
            Runnable producerRunnable = new Runnable()
            {
                public void run()
                {
                    while (true)
                    {
                        producer.setValue();
                    }
                }
            };
            Runnable customerRunnable = new Runnable()
            {
                public void run()
                {
                    while (true)
                    {
                        customer.getValue();
                    }
                }
            };
            Thread producerThread = new Thread(producerRunnable);
            Thread CustomerThread = new Thread(customerRunnable);
            producerThread.start();
            CustomerThread.start();
        }
    }
    

    运行结果如下

    Set的值是:1564733938518_27520480474279
    Get的值是:1564733938518_27520480474279
    Set的值是:1564733938518_27520480498378
    Get的值是:1564733938518_27520480498378
    Set的值是:1564733938518_27520480540254
    Get的值是:1564733938518_27520480540254
    ······
    

    生产者和消费者交替运行,生产者生产一个字符串,缓冲区为满,消费者消费一个字符串,缓冲区为空,循环往复,满足生产者/消费者模型。

    await()/signal()生产者/消费者模型

    缓冲区

    public class ValueObject {
    
        public static String value = "";
    
    }
    

    ThreadDomain48继承ReentrantLock,set方法生产,get方法消费

    public class ThreadDomain48 extends ReentrantLock
    {
        private Condition condition = newCondition();
    
        public void set()
        {
            try
            {
                lock();
                while (!"".equals(ValueObject.value))
                    condition.await();
                ValueObject.value = "123";
                System.out.println(Thread.currentThread().getName() + "生产了value, value的当前值是" + ValueObject.value);
                condition.signal();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            finally
            {
                unlock();
            }
        }
    
        public void get()
        {
            try
            {
                lock();
                while ("".equals(ValueObject.value))
                    condition.await();
                ValueObject.value = "";
                System.out.println(Thread.currentThread().getName() + "消费了value, value的当前值是" + ValueObject.value);
                condition.signal();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            finally
            {
                unlock();
            }
        }
    }
    

    MyThread41启动两个生产线程和一个消费线程

    public class MyThread41 {
        public static void main(String[] args)
        {
            final ThreadDomain48 td = new ThreadDomain48();
            Runnable producerRunnable = new Runnable()
            {
                public void run()
                {
                    for (int i = 0; i < Integer.MAX_VALUE; i++)
                        td.set();
                }
            };
            Runnable customerRunnable = new Runnable()
            {
                public void run()
                {
                    for (int i = 0; i < Integer.MAX_VALUE; i++)
                        td.get();
                }
            };
            Thread ProducerThread1 = new Thread(producerRunnable);
            ProducerThread1.setName("Producer1");
            Thread ProducerThread2 = new Thread(producerRunnable);
            ProducerThread2.setName("Producer2");
            Thread ConsumerThread = new Thread(customerRunnable);
            ConsumerThread.setName("Consumer");
            ProducerThread1.start();
            ProducerThread2.start();
            ConsumerThread.start();
        }
    }
    

    输出结果如下

    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    

    为什么Producer2无法生产,消费者无法消费呢?是因为此时缓冲区为满,Producer1的notify()应该唤醒Consumer却唤醒了Producer2,导致Producer2因为缓冲区为满和Consumer没有被唤醒而处于waiting状态,此时三个线程均在等待,出现了假死。
    解决方案有两种:
    1.让生产者唤醒所有线程,在set方法中使用condition.signalAll();
    2.使用两个Condition,生产者Condition和消费者Condition,唤醒指定的线程;
    正常输入如下:

    ······
    Producer2生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer2生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer2生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    Producer1生产了value, value的当前值是123
    Consumer消费了value, value的当前值是
    ······
    
  • 相关阅读:
    C语言利用按位与、按位或转换大小写字母
    综合布线知识点总结
    C语言 计算阶乘
    C语言位运算符详解
    docker-compose的flask自动部署
    redis集群的布置
    fatal: unable to auto-detect email address (got 'CC@LAPTOP-UPQ1N1VQ.(none)')
    使用ImagesPipeline时候报错为:ModuleNotFoundError: No module named 'scrapy.contrib'
    多任务
    json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (ch
  • 原文地址:https://www.cnblogs.com/Java-Starter/p/11289721.html
Copyright © 2011-2022 走看看