菜鸡的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 类的支持

猜你喜欢

转载自www.cnblogs.com/mysterious-killer/p/10140738.html