zoukankan      html  css  js  c++  java
  • 菜鸡的Java笔记 生产者与消费者

    生产者与消费者
            代码要求知道做什么用即可
            线程间的通讯问题以及 Object 类的支持
            
        基础模型
            现在希望实现一种数据的生产和取出的操作形式,即:有两个甚至更多的线程对象,这样的线程分为生产者线程和消费者线程
            那么最理想的状态是生产者每生产完一条完整的数据之后,消费者就要取走这个数据,并且进行输出的打印
            现在假设要输出的信息有这样两个:
                title = 帅帅, content = 一个学生;
                title = 可爱的小动物, content = 小猫咪;
                
            范例:程序的初期实现

    package cn.mysterious.actualcombat;
    class Info{
        private String title;
        private String 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;
        }
    }
    class Producptor implements Runnable{
        private Info info = null;
        public Producptor(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                if (i % 2 == 0) { // 偶数
                    this.info.setTitle("帅帅");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    this.info.setContent("一个学生");
                }else {
                    this.info.setTitle("可爱的动物");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    this.info.setContent("小猫咪");
                }
            }
        }
        
    }
    class Consumer implements Runnable{
        private Info info = null;
        public Consumer(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(this.info.getTitle() + "-->" + this.info.getContent());
            }
        }
    }
    public class ActualCombat{
        public static void main(String[] args){
            Info info = new Info();
            Producptor p = new Producptor(info);
            Consumer c = new Consumer(info);
            new Thread(p).start();
            new Thread(c).start();
    
        }
    }

               
            通过以上的执行可以发现有两个问题:
                第一:数据错位了
                第二:重复生产,重复取出
                
        解决数据不同步问题
            要想解决同步问题一定使用同步代码块或者是同步方法,既然要同步,那么肯定要将设置属性和取得的属性的内容都统一交给 Info 完成
            
            范例:

    package cn.mysterious.actualcombat;
    class Info{
        private String title;
        private String content;
        public synchronized void set(String content, String title){
            this.title = title;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            this.content = content;
        }
        public synchronized void get(){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(this.title + "-->" +this.content );
        }
    }
    class Producptor implements Runnable{
        private Info info = null;
        public Producptor(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                if (i % 2 == 0) { // 偶数
                    this.info.set("帅帅","一个学生");
                }else {
                    this.info.set("可爱的动物","小猫咪");
                }
            }
        }
        
    }
    class Consumer implements Runnable{
        private Info info = null;
        public Consumer(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                this.info.get();
            }
        }
    }
    public class ActualCombat{
        public static void main(String[] args){
            Info info = new Info();
            Producptor p = new Producptor(info);
            Consumer c = new Consumer(info);
            new Thread(p).start();
            new Thread(c).start();
    
        }
    }

               
                所有的设置和取得数据的操作都交给了同步方法完成
                现在同步问题解决了,但是重复问题更严重了
                
        解决重复操作
            如果要想解决重复问题,那么必须加入等待与唤醒的处理机制,而这样的操作方法是有 Object 类所提供的
            在 Object 类中提供有如下几种方法:
                等待: public final void wait() throws InterruptedException{}
                唤醒第一个等待线程: public final void notify();
                唤醒全部等待线程: public final void notifyAll();
                
            范例:修改Info类

    package cn.mysterious.actualcombat;
    class Info{
        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) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } // 没有生产,可以生产
            this.title = title;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            this.content = content;
            this.flag = false;// 表示生产过了
            super.notify();
        }
        public synchronized void get(){
            if (this.flag = true) { // 此时应该生产,不应该取走数据
                try {
                    super.wait(); // 等待
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(this.title + "-->" +this.content );
            this.flag = true; // 表示取走了
            super.notify();
        }
    }
    class Producptor implements Runnable{
        private Info info = null;
        public Producptor(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                if (i % 2 == 0) { // 偶数
                    this.info.set("帅帅","一个学生");
                }else {
                    this.info.set("可爱的动物","小猫咪");
                }
            }
        }
        
    }
    class Consumer implements Runnable{
        private Info info = null;
        public Consumer(Info info){
            this.info = info;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 50; i++) {
                this.info.get();
            }
        }
    }
    public class ActualCombat{
        public static void main(String[] args){
            Info info = new Info();
            Producptor p = new Producptor(info);
            Consumer c = new Consumer(info);
            new Thread(p).start();
            new Thread(c).start();
    
        }
    }

               
            面试题:请解释 sleep() 与 wait() 的区别?
                sleep() 是 Thread 类定义的方法,在休眠一定时间之后自己唤醒
                wait() 是 Object 类定义的方法,表示线程要等待执行,必须通过 notify(),notifyAll() 方法来进行唤醒

        总结
            生产者和消费者这是一个模型,完整的体现了线程的同步, Object 类的支持

  • 相关阅读:
    一、服务器控件生命周期
    ArcGIS中的Analysis Tool中的Overlay
    谓词和操作
    联接基础知识SQL中
    修改windows右键菜单
    二、服务器控件的呈现
    连接池
    数据库中的NULL(空值)
    有关在SQL中使用函数
    锁的概述及例子讲解(转贴)
  • 原文地址:https://www.cnblogs.com/mysterious-killer/p/10140738.html
Copyright © 2011-2022 走看看