生产者-消费者问题

2019-01-26  本文已影响0人  秋笙fine

1.生产者-消费者问题的产生

生产者和消费者指的是两个不同的线程类对象,操作同一资源的情况。具体操作情况如下。

1.生产者负责生产数据,消费者负责取走数据
2.生产者每生产完一组数据之后,消费者就要取走一组数据

第一组数据:title="sl",content="Good Student"
第二组数据:title=“动物”,content="sheep"

package TestDemo;

class Info{
    String name;
    String content;
    /**
     * @return the content
     */
    public String getContent() {
        return content;
    }
    /**
     * @param content the content to set
     */
    public void setContent(String content) {
        this.content = content;
    }
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
}
class Productor implements Runnable{
    private Info info;
    public Productor(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(i%2==0){
                this.info.setName("animal");
                try {
                    Thread.sleep(100);

                } catch (Exception e) {
                    //TODO: handle exception
                }
                this.info.setContent("sheep");
                continue;
            }
            this.info.setName("sl");
            try {
                Thread.sleep(100);

            } catch (Exception e) {
                //TODO: handle exception
            }
            this.info.setContent("Good student");
        }
        
    }
}

class Customer implements Runnable{
    private Info info;
    public Customer(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);

            } catch (Exception e) {
                //TODO: handle exception
            }
            System.out.println(this.info.getName()+"===="+this.info.getContent());
        }
    }
}

public class TestDemo{
    
    public static void main(String[] args){
     Info info=new Info();
     new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
     new Thread(new Customer(info)).start();
    }   
}

结果


image.png image.png

发现了两个严重问题:
1.数据错位
2.数据重复取出,数据重复设置

1.解决数据错位问题
数据错位完全是因为非同步的操作所造成的,所以应该使用同步处理。并且两个数据要同时设置。同时取出。因而对set,get进行同步方法

package TestDemo;

class Info{
    String name;
    String content;
    public synchronized void set(String name,String content){
        this.name=name;
        try {
            Thread.sleep(200);

        } catch (Exception e) {
            //TODO: handle exception
        }
        this.content=content;
    }
    public synchronized void get(){
        try {
            Thread.sleep(100);
        } catch (Exception e) {
            //TODO: handle exception
        }
        System.out.println(this.name+"==="+this.content);
    }
}
class Productor implements Runnable{
    private Info info;
    public Productor(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(i%2==0){
                this.info.set("animal", "sheep");
                continue;
            }
            this.info.set("sl", "Good student");
        }
        
    }
}

class Customer implements Runnable{
    private Info info;
    public Customer(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
        
            this.info.get();
        }
    }
}

public class TestDemo{
    
    public static void main(String[] args){
     Info info=new Info();
     new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
     new Thread(new Customer(info)).start();
    }
}

此时,数据错位问题得到了解决,但是重复问题更加严重了。


image.png

然后我们解决重复问题:
如果要想实现整个代码的操作,必须加入等待与唤醒机制,在Object类里面有专门的处理方法

2.Object类对多线程的支持

Object类中有如下方法:
等待:public final void wait() throws InterruptedException
唤醒第一个等待线程:public final void notify();
唤醒全部等待线程,哪个优先级高,唤醒哪个:
public final void notifyAll();

解决重复问题:修改info方法

package TestDemo;

class Info{
    String name;
    String content;
    private boolean flag=true;
    //flag为true表示可以生产,但是不能取走
    //flag为false表示可以取走但是不能生产
    public synchronized void set(String name,String content){
        //如果重复进行set方法
        if(this.flag==false){
            try {
                super.wait();//让线程等待
            } catch (Exception e) {
                //TODO: handle exception
            }
            
        }

        this.name=name;
        try {
            Thread.sleep(200);

        } catch (Exception e) {
            //TODO: handle exception
        }
        this.content=content;
        this.flag=false;//修改生产标记
        super.notify();//唤醒其它等待线程
    }
    public synchronized void get(){
        if(this.flag==true){
            try {
                super.wait();
            } catch (Exception e) {
                //TODO: handle exception
            }
        }
        try {
            Thread.sleep(100);
        } catch (Exception e) {
            //TODO: handle exception
        }
        System.out.println(this.name+"==="+this.content);
        this.flag=true;
        super.notify();
    }
}
class Productor implements Runnable{
    private Info info;
    public Productor(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(i%2==0){
                this.info.set("animal", "sheep");
                continue;
            }
            this.info.set("sl", "Good student");
        }
        
    }
}

class Customer implements Runnable{
    private Info info;
    public Customer(Info info){
        this.info=info;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
        
            this.info.get();
        }
    }
}

public class TestDemo{
    
    public static void main(String[] args){
     Info info=new Info();
     new Thread(new Productor(info)).start();//由于生产者消费者类都是Runnable子类,可以传入构造
     new Thread(new Customer(info)).start();
    }   
}
image.png

成功了。

面试题:请解释sleep与wait区别:
sleep()是Thread类定义的方法,wait()是Object类定义的方法
sleep()可以设置休眠时间,时间一到自动唤醒,wait需要notify方法来唤醒。

总结

生产者-消费者模型是一个非常经典的多线程处理模型。

上一篇 下一篇

猜你喜欢

热点阅读