生产者消费者模式

摘要:
目录单生产和消费模式多生产和消费模式通过管道实现线程通信单生产和消费模式在Java中,负责产生数据的模块的是生产者,负责使用数据的模块是消费者,生产者消费者解决数据的平衡问题,即先有数据才能使用,没有数据时消费者需要等待。
目录

单生产和消费模式

在Java中,负责产生数据的模块的是生产者,负责使用数据的模块是消费者,生产者消费者解决数据的平衡问题,即先有数据才能使用,没有数据时消费者需要等待。

例如:有一个饭店,它有一个厨师和一个服务员,服务员必须等厨师把菜做好了,通知到服务员才能上菜,然后返回继续等待,厨师代表生产者,服务员代表消费者,两个任务在被消费和生产同时运行。

public class Text17 {
    public static void main(String[] args) {
        ValueOP valueOP=new ValueOP();
        //测试生产-消费
        ProductThread productThread=new ProductThread(valueOP);
        ConsumerThread consumerThread=new ConsumerThread(valueOP);

        productThread.start();
        consumerThread.start();
    }
}
//定义线程类模拟生产者
class  ProductThread extends Thread
{
    private ValueOP obj;
    public  ProductThread(ValueOP obj)
    {
        this.obj=obj;
    }

    @Override
    public void run() {
       while (true)
       {
           try {
               obj.SetValue();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}
class  ConsumerThread extends Thread
{
    private ValueOP obj;
    public  ConsumerThread(ValueOP obj)
    {
        this.obj=obj;
    }

    @Override
    public void run() {
        while (true)
        {
            try {
                obj.GetValue();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//SetValue用来设置值,如果不为空就不设置值,如果GetValue为空,就等待不读取,这样前一个设置后一个读取
class  ValueOP
{
    public  String value="";
    //修改值方法
    public  void  SetValue() throws InterruptedException {
        synchronized (this)
        {
            //如果不是空字符串就等待
            if(!value.equalsIgnoreCase(""))
            {
                this.wait();
            }
            //如果是空串就设置value值
            String value=System.currentTimeMillis()+"-"+System.nanoTime();
            System.out.println("set设置的是"+value);
            this.value=value;
            this.notify();
        }
    }
    //读取字段
    public  void GetValue() throws InterruptedException {
        synchronized (this)
        {
            //如果是空字符串就等待
            if(value.equalsIgnoreCase(""))
            {
                this.wait();
            }
            //不是空串就读取,并赋值为空
            System.out.println("get的值是:"+value);
            this.value="";
            this.notify();
        }
    }
}

image-20210317233223367

这样生产与消费交替运行

多生产和消费模式

一个饭店有多个厨师和服务员,当厨师们做菜过快了,导致服务员上菜速度跟不上,导致菜堆积在窗口,这时候要让厨师停止生产,等待服务员把菜上完,再继续做菜。如果服务员们上菜速度太快了,厨师没有做完,多名服务员又想上菜,这时候要等待厨师做菜。

public class Text17 {
    public static void main(String[] args) {
        ValueOP valueOP=new ValueOP();
        //测试生产-消费
        ProductThread productThread=new ProductThread(valueOP);
        ProductThread productThread2=new ProductThread(valueOP);
        ConsumerThread consumerThread=new ConsumerThread(valueOP);
        ConsumerThread consumerThread2=new ConsumerThread(valueOP);
        productThread.start();
        productThread2.start();;
        consumerThread.start();
        consumerThread2.start();
    }
}
//定义线程类模拟生产者
class  ProductThread extends Thread
{
    private ValueOP obj;
    public  ProductThread(ValueOP obj)
    {
        this.obj=obj;
    }

    @Override
    public void run() {
       while (true)
       {
           try {
               obj.SetValue();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}
class  ConsumerThread extends Thread
{
    private ValueOP obj;
    public  ConsumerThread(ValueOP obj)
    {
        this.obj=obj;
    }

    @Override
    public void run() {
        while (true)
        {
            try {
                obj.GetValue();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//SetValue用来设置值,如果不为空就不设置值,如果GetValue为空,就等待不读取,这样前一个设置后一个读取
class  ValueOP
{
    public  String value="";
    //修改值方法
    public  void  SetValue() throws InterruptedException {
        synchronized (this)
        {
            //如果不是空字符串就等待
            while (!value.equalsIgnoreCase(""))
            {
                this.wait();
            }
            //如果是空串就设置value值
            String value=System.currentTimeMillis()+"-"+System.nanoTime();
            System.out.println("set设置的是"+value);
            this.value=value;
            this.notifyAll();
        }
    }
    //读取字段
    public  void GetValue() throws InterruptedException {
        synchronized (this)
        {
            //如果是空字符串就等待
            while (value.equalsIgnoreCase(""))
            {
                this.wait();
            }
            //不是空串就读取,并赋值为空
            System.out.println("get的值是:"+value);
            this.value="";
            this.notifyAll();
        }

    }
}

image-20210319001051071

在多生产消费的环境notify不能保证是唤醒消费者,如果生产者唤醒生产者就会出现假死情况。

通过管道实现线程通信

在java.io包中的pipeStream管道流用于在线程之间传送数据,一个线程发送数据到输出管道,另一个线程从输入管道读取数据,相关的类包括:pidedInputStream和pipedoutStream,pipedReader和pepedWriter

import java.awt.print.PrinterIOException;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class TextWrite {
    public static void main(String[] args) throws IOException {
        PipedInputStream inputStream=new PipedInputStream();
        PipedOutputStream outputStream=new PipedOutputStream();
        inputStream.connect(outputStream);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    WriteData(outputStream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ReadData(inputStream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    //定义方法向管道流中写入数据
public  static  void  WriteData(PipedOutputStream outputStream) throws IOException {
        for (int i = 0; i <100 ; i++) {
            String data=""+i;
            outputStream.write(data.getBytes());//把字节数组写入到输出管道中
        }
        outputStream.close();
}
//从管道流中读取数据
    public  static  void  ReadData(PipedInputStream inputStream) throws IOException {
        byte[] bytes=new byte[1024];
        int len=inputStream.read(bytes);//返回读到的字节数,没有读到返回-1
        while (len != -1) {
            System.out.println(new String(bytes, 0, len));
            len=inputStream.read(bytes);//继续从管道读取数据
        }
        inputStream.close();
    }
}

image-20210319003236751

免责声明:文章转载自《生产者消费者模式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇一个被慕课网拿去做Java就业班终极项目的开源商城项目,推荐给大家集合与多线程面试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

多线程详细介绍

什么是进程线程:我们来看一下自己的任务管理器 这里的每一项都是一个进程,我们的发布的每一个应用程序都需要一个进程去运行,在一个进程内可以有多个线程去计算执行程序。我们看下面的图片: 我们可以看一下进程和线程的数量,很明显可以看出,线程和进程的关系。我们的每一个操作都需要一个线程来执行,鼠标的点击就需要线程去响应我们的操作。 现在我们不难理解,我们一个应...

C#多线程(二)

一、线程池每次创建一个线程,都会花费几百微秒级别的时间来创建一个私有的局部栈,每个线程默认使用1M的内存。这个可以在使用Thread类的构造函数时设置: [csharp] view plaincopyprint?  new Thread(new ThreadStart(Go), 2);   new Thread(new ParameterizedT...

Java面试——多线程面试题总结

0.前言 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分,本文汇总了常见的一些多线程面试题。 一些问题,比如volatile关键词的作用,synchronized和ReentrantLock的区别,wait()和sleep()的区别等等问题,已经在之前写过的文章中提到过了,这里就不赘述了,有兴趣可以查看以下几篇文章:Java并发——线程同...

多线程并发详解

一、Java 线程实现/创建方式   注意:   • 新建的线程不会自动开始运行,必须通过start( )方法启动   • 不能直接调用run()来启动线程,这样run()将作为一个普通方法立即执行,执行完毕前其他线程无法并发执行   • Java程序启动时,会立刻创建主线程,main就是在这个线程上运行。当不再产生新线程时,程序是单线程的  1.1 继承...

用最简单的方式在C#中使用多线程加速耗时的图像处理算法的执行(多核机器)。

图像处理中,有很多算法由于其内在的复杂性是天然的耗时大户,加之图像本身蕴涵的数据量比一般的对象就大,因此,针对这类算法,执行速度的提在很大程度上依赖于硬件的性能,现在流行的CPU都是至少2核的,稍微好点的4核,甚至8核,因此,如果能充分利用这些资源,必将能发挥机器的强大优势,为算法的执行效果提升一个档次。 在单核时代,多线程程序的主要目的是防止UI假死,而...

用Python实现多核心并行计算

平常写的程序,无论是单线程还是多线程,大多只有一个进程,而且只能在一个核心里工作。所以很多应用程序即使正在满载运行,在任务管理器中CPU使用量还是只有50%(双核CPU)或25%(四核CPU) 如果能让一个程序自己建立出多个进程,并且让它们并行运行,那么就可以在不同cpu核心上同时运行,进而实现并行计算啦。 Python的并行计算就是这么做的。 之前的理解...