美文网首页
Java线程操作实现生产者与消费者模型

Java线程操作实现生产者与消费者模型

作者: 撸码小狂魔 | 来源:发表于2020-05-25 22:22 被阅读0次
基本模型
class Message {  //描述公共空间
    private String title;
    private String content;

    public void setContent(String content) {
        this.content = content;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public String getTitle() {
        return title;
    }

}

class ProducerThread implements Runnable {
    private final Message message;    //获得message的引用

    public ProducerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            this.message.setTitle("title: " + i);
            this.message.setContent("content: " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class ConsumerThread implements Runnable {

    private final Message message;    //获得message的引用

    public ConsumerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run(){

        for (int i = 0; i < 100; i++) {
            System.out.println("消费者:" + this.message.getTitle() + this.message.getContent());

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

public class Test {

    public static void main(String[] args) {

        Message message = new Message();        //实例化Message
        new Thread(
                new ProducerThread(message)
        ).start();                  //启动生产者线程

        new Thread(
                new ConsumerThread(message)
        ).start();                  // 启动消费者线程

    }

}

此时的代码仅仅是是实现了两个线程彼此独立的操作交互,但是通过最终的执行结果可以清楚的发现当前的程序代码之中存在如下的几个设计问题:

  • 在生产着没有完成向生产的时候哦虎消费者就已经获取数据了,获取的数据就属于一个半成品数据;
  • 如果说现在消费者性能高于生产者,则会出现爱你同一个信息重复消费的问题。

解决数据同步问题

在java的程序之中,如果想要实现数据的同步处理,那么肯定要使用synchronized来完成,如果要完成的话那么肯定就需要同步代码块或者是同步方法,之所以现在出现了不同步的问题,主要是没有在生产的过程里面对数据的操作进行锁定。


image.png

范例:修改程序的结构代码

class Message {  //描述公共空间
    private String title;
    private String content;


    public synchronized void set(String title,String content){
        this.content = content;
        this.title = title;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized  String get(){
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return  this.title + this.content;

    }


}

class ProducerThread implements Runnable {
    private final Message message;    //获得message的引用

    public ProducerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            this.message.set(
                    "title: " + i,"content: "+i
            );
        }
    }

}

class ConsumerThread implements Runnable {

    private final Message message;    //获得message的引用

    public ConsumerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run(){

        for (int i = 0; i < 100; i++) {
            System.out.println(this.message.get());
        }

    }
}

public class Test {

    public static void main(String[] args) {

        Message message = new Message();        //实例化Message
        new Thread(
                new ProducerThread(message)
        ).start();                  //启动生产者线程

        new Thread(
                new ConsumerThread(message)
        ).start();                  // 启动消费者线程

    }

}

通过当前的程序的改进可以发现此时的代码已经完全可以正确的实现相关的内容的配置,并且没有任何的数据错位,所以解决了数据混乱的问题,但是另外一个问题还没有解决:重复生产数据和重复消费数据。

解决线程重复操作问题

而要想实现这样的功能就必须采用线程的同步、等待与唤醒的处理机制,而这样的处理机制的操作全部定义在了Object类里面,在Object类中提供有如下的几个与线程有关的操作方法。

image.png

特别重要的提示:以上这几个处理方法是进行线程控制的,但是这些方法都是在synchronized方法中才去使用的,同时这些方法属于最原始的多线程协作控制。如果真的用这些操作进行开发,那么整个项目里面基本上对死锁的情况就会频发。

class Message {  //描述公共空间
    private String title;
    private String content;
    private boolean flag = true;    //设置一个标志位(红绿灯)

    //flag = true:表示可以生产,但是无法进行消费,
    //flag = false:表示可以消费,但是无法生产

    public synchronized void set(String title,String content){
        if (this.flag == false) {   //不允许生产,但是允许消费
            try {
                super.wait();   //等到消费者线程执行完毕后唤醒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.content = content;
        this.title = title;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.flag = false;      //表示生产完成,可以消费
        super.notify();         //唤醒其它等待线程
    }

    public synchronized  String get(){

        if(this.flag == true){  //不允许消费,只允许生产
            try {
                super.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        this.flag = true;      //表示消费完成,可以生产
        super.notify();         //唤醒其它等待线程

        return  this.title + this.content;
    }


}

class ProducerThread implements Runnable {
    private final Message message;    //获得message的引用

    public ProducerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            this.message.set(
                    "title: " + i,"content: "+i
            );
        }
    }

}

class ConsumerThread implements Runnable {

    private final Message message;    //获得message的引用

    public ConsumerThread(Message message) {
        this.message = message;
    }

    @Override
    public void run(){

        for (int i = 0; i < 100; i++) {
            System.out.println(this.message.get());
        }

    }
}

public class Test {

    public static void main(String[] args) {

        Message message = new Message();        //实例化Message
        new Thread(
                new ProducerThread(message)
        ).start();                  //启动生产者线程

        new Thread(
                new ConsumerThread(message)
        ).start();                  // 启动消费者线程

    }

}

相关文章

  • Java生产者/消费者模型的一种实现

    本文主要介绍java中生产者/消费者模式的实现,对java线程锁机制的一次深入理解。 生产者/消费者模型 生产者/...

  • 多进程、多线程、生成器实现生产者消费者模型

    多线程实现 多线程实现生产者消费者模型的逻辑十分简单,生产者与消费者之间通过队列来进行通讯,所以生产者不用等待消费...

  • 生产者-消费者 模型

    生产者与消费者基本程序模型 在多线程开发过程之中最为著名的案例就是生产者与消费者操作,该操作的主要流程如下:生产者...

  • Java 并发编程——生产者与消费者

    1. 生产者与消费者 1.1 程序基本实现(问题引出) 生产者与消费者是线程操作的经典案例,即:生产者不断生产,消...

  • 线程通信-wait(notify)

    知识总结 多线程通信最经典的模型就是生产者消费者模式,java中有队列LinkedList可以实现该模式,做到通信...

  • Java线程操作实现生产者与消费者模型

    此时的代码仅仅是是实现了两个线程彼此独立的操作交互,但是通过最终的执行结果可以清楚的发现当前的程序代码之中存在如下...

  • kotlin协程高级玩法之生产者与消费者实现

    简述 在java中通常用LinkedBlockingQueue去实现一个阻塞队列,目的是实现生产者与消费者模型,该...

  • Java 阻塞队列

    简介 java 的阻塞队列是应用在多线程中,尤其适合生产者和消费者模式,阻塞队列支持阻塞操作,线程安全,已经实现了...

  • java同步

    生产者与消费者问题。 概念 在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的...

  • java 中线程协作

    线程协作 多线程协作的典型场景,生产者消费者模型。JAVA 中提供的线程阻塞和线程唤醒 Api 被弃用的 susp...

网友评论

      本文标题:Java线程操作实现生产者与消费者模型

      本文链接:https://www.haomeiwen.com/subject/fviuahtx.html