在计算中,生产者 - 消费者问题(也称为有界缓冲问题)是多进程同步问题的典型示例。该问题描述了两个进程,即生产者和使用者,它们共享一个用作队列的通用固定大小缓冲区。

  • 生产者的工作是生成数据,将其放入缓冲区,然后重新开始。
  • 同时,消费者正在消费数据(即从缓冲区中删除数据),一次一件。

问题
确保生成器不会尝试将数据添加到缓冲区(如果已满)并且使用者不会尝试从空缓冲区中删除数据。

解决方案
如果缓冲区已满,生产者要么进入睡眠状态要么丢弃数据。消费者下次从缓冲区中删除项目时,它会通知生产者,生产者再次开始填充缓冲区。以同样的方式,如果消费者发现缓冲区为空,则消费者可以进入睡眠状态。下一次生产者将数据放入缓冲区时,它会唤醒睡眠消费者。
解决方案不充分可能导致两个进程等待唤醒的死锁。

推荐阅读- 在多线程JAVAJAVA中同步线程间通信

JAVA中,线程的生产者消费者类的实施

  • 一个LinkedList的名单 -存储在队列中的作业清单。
  • 可变容量 - 检查列表是否已满
  • 一种控制从此列表中插入和提取的机制,以便我们不会在列表中填充,如果它是空的,则不会插入到列表中,如果它是空的,则不从中删除。

 

 

// Java program to implement solution of producer
// consumer problem.
import java.util.LinkedList;
public class Threadexample
{
    public static void main(String[] args)
                        throws InterruptedException
    {
        // Object of a class that has both produce()
        // and consume() methods
        final PC pc = new PC();
        // Create producer thread
        Thread t1 = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    pc.produce();
                }
                catch(InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        });
        // Create consumer thread
        Thread t2 = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    pc.consume();
                }
                catch(InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        });
        // Start both threads
        t1.start();
        t2.start();
        // t1 finishes before t2
        t1.join();
        t2.join();
    }
    // This class has a list, producer (adds items to list
    // and consumber (removes items).
    public static class PC
    {
        // Create a list shared by producer and consumer
        // Size of list is 2.
        LinkedList<Integer> list = new LinkedList<>();
        int capacity = 2;
        // Function called by producer thread
        public void produce() throws InterruptedException
        {
            int value = 0;
            while (true)
            {
                synchronized (this)
                {
                    // producer thread waits while list
                    // is full
                    while (list.size()==capacity)
                        wait();
                    System.out.println("Producer produced-"
                                                  + value);
                    // to insert the jobs in the list
                    list.add(value++);
                    // notifies the consumer thread that
                    // now it can start consuming
                    notify();
                    // makes the working of program easier
                    // to  understand
                    Thread.sleep(1000);
                }
            }
        }
        // Function called by consumer thread
        public void consume() throws InterruptedException
        {
            while (true)
            {
                synchronized (this)
                {
                    // consumer thread waits while list
                    // is empty
                    while (list.size()==0)
                        wait();
                    //to retrive the ifrst job in the list
                    int val = list.removeFirst();
                    System.out.println("Consumer consumed-"
                                                    + val);
                    // Wake up producer thread
                    notify();
                    // and sleep
                    Thread.sleep(1000);
                }
            }
        }
    }
}

输出:

Producer produced-0
Producer produced-1
Consumer consumed-0
Consumer consumed-1
Producer produced-2

重点

  • PC类(具有生成和使用方法的类)中,添加了一个作业链接列表和列表容量,以检查生成器是否在列表已满时不生成。
  • Producer类中,该值初始化为0。
    • 此外,我们有一个无限的外部循环来插入列表中的值。在这个循环中,我们有一个synchronized块,所以一次只运行一个生产者或一个消费者线程。
    • 在将作业添加到列表之前存在内部循环,该列表检查作业列表是否已满,生产者线程放弃PC上的内部锁定并继续等待状态。
    • 如果列表为空,则控件传递到循环下方,并在列表中添加一个值。
  • Consumer类中,我们再次有一个无限循环来从列表中提取值。
    • 在里面,我们还有一个内部循环,用于检查列表是否为空。
    • 如果它是空的,那么我们让消费者线程放弃PC上的锁并将控制传递给生产者线程以产生更多的工作。
    • 如果列表不为空,我们绕过循环并从列表中删除一个项目。
  • 在这两种方法中,我们在所有语句的末尾使用notify。原因很简单,一旦你在列表中有东西,你可以让消费者线程消费它,或者如果你已经消费了东西,你可以让生产者产生一些东西。
  • 两个方法结束时的sleep()只是使程序的输出以步进方式运行,而不是一次显示所有内容,以便您可以看到程序中实际发生的情况。
 
转载请保留页面地址:https://www.breakyizhan.com/java/4964.html
扫描二维码添加微信 
  • ,每次淘宝领取淘宝优惠券,淘宝购物更优惠。现在添加微信,还可以领取机械键盘50元优惠券!添加微信后回复机械键盘即可领取!
    支持我们,就用微信淘宝!