温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java多线程中的生产者与消费者案例讲解

发布时间:2021-07-28 09:07:18 来源:亿速云 阅读:102 作者:chen 栏目:开发技术

这篇文章主要讲解了“Java多线程中的生产者与消费者案例讲解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程中的生产者与消费者案例讲解”吧!

目录
  • 前言

    • 工具

    • 知识点

    • 设计思路

    • 具体步骤

  • 总结

    前言

    想象一下生活中哪些是和线程沾边的?饭店炒菜就是一个很好的例子

    首先客人要吃菜,前提是厨师要炒好,也就是说,厨师不炒好的话客人是没有饭菜的。这时候,厨师就是一个线程,客人拿菜就是另一个线程。

    工具

    jdk13,IDEA2019.1.4

    知识点

    Thread、Runnable、synchronized、面向对象知识(继承、封装、接口、方法重写)、条件判断以及线程的一些其他知识点

    设计思路

    首先要有两个线程,也就是说要两个类,分别是Producer(生产者)和Consumer(消费者)。

    由于我们是模拟厨师与客人之间的互动,也就是说还需要一个类来封装信息:Message(类)。

    然后,避免线程之间发生数据混乱的情况,肯定还需要使用synchronized来进行线程同步。

    具体步骤

    首先我们来一份没有用synchronized的代码,先看看效果:

    public class Message {
        private String title;
        private String content;
        Message(){
        };
        public Message(String title, String content) {
            this.title = title;
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    }
    /*
    * 定义生产者类Producer
    * */
    class Producer implements Runnable{
        private Message msg=null;
        public Producer(Message msg) {
            this.msg = msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.setTitle("喜欢夜雨吗?");
                    try {
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        System.out.println(e);
                    }
                    this.msg.setContent("是的呢!");
                }else {
                    this.msg.setTitle("还不关注我吗?");
                    try {
                        Thread.sleep(100);
                    }catch (InterruptedException e){
                        System.out.println(e);
                    }
                    this.msg.setContent("好的呢!");
                }
            }
        }
    }
    /*
    * 定义消费者类Consumer
    * */
    class Consumer implements Runnable{
        private Message msg=null;
        public Consumer(Message msg) {
            this.msg = msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                try {
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    System.out.println(e);
                }
                System.out.println(this.msg.getTitle()+"--->"+this.msg.getContent());
            }
        }
    }
    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }

    看看运行结果:

    Java多线程中的生产者与消费者案例讲解

    看仔细咯,发生了数据错乱啊,Title与Content没有一一对应欸。咋办?

    能咋办,改代码呗。

    发生数据混乱的原因完全是因为,生产者线程还没生产的时候,消费者就已经消费了(至于消费的啥我也不知道,我也不敢问啊)。所以造成了数据混乱,不过我们上面说了啊,要使用synchronized来让线程同步一下。但是又会出问题,我们接着往下看

    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }
    class Message{
        private String title,content;
        public synchronized void set(String title,String content){
            this.title=title;
            this.content=content;
        }
        public synchronized void get(){
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            System.out.println(this.title+"-->"+this.content);
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    }
    class Producer implements Runnable{
        private Message msg=null;
        Producer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.set("喜欢夜雨吗?","是的呢!");
                }else {
                    this.msg.set("还不关注吗?","好的呢!");
                }
            }
        }
    }
    class Consumer implements Runnable{
        private Message msg=null;
        Consumer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                this.msg.get();
            }
        }
    }

    我又重新封装了一些方法,然后运行的时候,wc,数据倒是不混乱了,但是呢,数据重复了一大堆。

    Java多线程中的生产者与消费者案例讲解

    为啥会出现这个问题呢?最后想了一下,会出现这种问题的,就是因为线程的执行顺序的问题。我们想要实现的效果是生产者线程执行了之后,让生产者线程等待,而后让消费者线程执行,等待消费者线程执行完成之后就又让生产者线程继续执行。后来我又查了查官方文档,发现Object类中专门有三个方法是与线程相关的:

    方法描述
    public final void wait() throws InterruptedException线程的等待
    public final void notify()唤醒第一个等待线程
    public final void notifyAll()

    当我看到这些方法的时候,心里愣了一下,这不就是我们想要的方法吗,用wait()方法来让生产者线程等待,然后运行消费者线程,等消费者线程执行完了之后又让生产者线程去执行。这其中我们用true和false来表示运行开始和运行暂停。

    最后我们来看看完成品的代码:

    class TestDemo{
        public static void main(String[] args) {
            Message msg=new Message();
            new Thread(new Producer(msg)).start();
            new Thread(new Consumer(msg)).start();
        }
    }
    class Message extends Exception{
        private String title,content;
        private boolean flag=true;
        // true表示正在生产,不要来取走,因为没由让消费者区走的
        // false表示可以取走,但是不能生产
        public synchronized void set(String title,String content){
            if (this.flag==false){
                try {
                    super.wait();
                }catch (InterruptedException e){
                    System.out.println(e);
                }
            }
            this.title=title;
            try {
                Thread.sleep(60);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            this.content=content;
            this.flag=true; // 生产完成,修改标志位
            super.notify(); // 唤醒等待线程
        }
        public synchronized void get(){
            if (flag==true) {// 已经生产好了,等待取走
                try {
                    super.wait();
                }catch (InterruptedException e){
                    System.out.println(e);
                }
            }
            try {
                Thread.sleep(60);
            }catch (InterruptedException e){
                System.out.println(e);
            }
            System.out.println(this.title+"-->"+this.content);
            this.flag=true;
            super.notify();
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    }
    class Producer implements Runnable{
        private Message msg=null;
        Producer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                if (i%2==0){
                    this.msg.set("喜欢夜雨吗?","是的呢!");
                }else {
                    this.msg.set("还不关注吗?","好的呢!");
                }
            }
        }
    }
    class Consumer implements Runnable{
        private Message msg=null;
        Consumer(Message msg){
            this.msg=msg;
        }
        @Override
        public void run() {
            for (int i=0;i<=50;i++){
                this.msg.get();
            }
        }
    }

    运行结果我就不贴了,你们自己去测试一下吧…

    总结

    这个案例完美的呈现了线程以及面向对象知识的综合运用,具有很强的实际操作性

    感谢各位的阅读,以上就是“Java多线程中的生产者与消费者案例讲解”的内容了,经过本文的学习后,相信大家对Java多线程中的生产者与消费者案例讲解这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI