生产者与消费者案例

手头有两个人(也就是两个类),一个做存操作,一个做取操作,并且只有当存完或者取完方可进行令一个操作。以此达到循环输出的存取操作。

第一步:先写测试生产者类与消费者类  和 线程操作Msg类

//生产者
public class Product implements Runnable{
    private Msg msg = null; //线程操作对象
    public Product (Msg msg){
        super();
        this.msg = msg;
    }
    @override
    public void run(){
        for(int i=0;i<10;i++){
            if(i%2==0){
                   try{
                    this.msg.set("男","胡明明");
                }catch{
                    e.printStackTrace();
                }else{
                    this.msg.set("女","肖体秀");
                }
            }
        }
    
    }

}


//消费者
public class Consumer implements Runnable{
    private Msg msg = null;
     public Consumer (Msg msg){
        super();
        this.msg = msg;
    }
    
    @override
    public void run(){
        for(int i=0;i<10;i++){
            try{
                this.msg.get();
            }catch{
                e.printStackTrance();
            }
        }
    }

}

//线程操作Msg类
public class Msg{
    private String title;
    private String content;
    private boolearn flag = true;//true:生产者可以生产,不能取  false:消费者可以取,生产者不能生产
//多个线程访问统一资源。要考虑到数据是否同步的问题,当线程进入睡眠或者等待其它线程会趁虚而入,所以在方法加上一把锁

    public synchrnoized void set (String title,String content){
        if(this.flag == false){//存线程等待
        System.out.println(Thread.currentThread().getName()+ "进入等待")
        super.wait();
        }
        this.title = title;
        this.content = content;
        this.flag = false;//存完成,改变标识
        System.out.println(Thread.currentThread.getNmae() + "睡眠,并唤醒睡眠或者等待的线程")
        super.notify();//唤醒第一个等待的线程(取)
    }

    public synchrnoized void get(){
        if(this.flag == true){//取等待
            super.wait();
        }
        System.out.println(Thread.currentThread().getName() + this.title +"-----" +             this.content)
    this.flag = false;//存完成,改变标识
    super.notify();//唤醒第一个等待的线程(存)
    }

    public static void main(String[] args){
        Msg msg = new Msg();//实例化对象
        new Thread(msg,"存线程1")。start();
        new Thread(msg,"存线程2")。start();
        //new Thread(msg,"取线程")。start();
    }

}

/**
*实际上这个也很好理解,假设有两个线程,存线程和取线程(两个不同的操作类)被cpu调用,进入队列,假
*设存线程先被执行**那么,先走for循环第次存(同步,别的线程进不来)胡明明,当准备走第1次时,再次进
*行存的操作,发现存不了了,因为要存一次取一次,故将该线程进入睡眠状态,也就数阻塞。所以在外面伺机*已久的取线程进来了,进行取得操作,并唤醒其它睡眠或者等待的线程(期间存线程可能已经被唤醒了,进行*了存的操作)。当再次准备继续走循环时,同样跟存一样,也是必须一取一存才可以,由于标识符的改变,故*取线程进入睡眠。以此类推
*/

//当只有存取线程的时候确实是交易输出,但是我加了一个存线程,进入死锁。解析如下:

假设存1存2线程分别进入run方法,但是只能有一个人才能做存操作,假设有幸是存1,那么存1存完后,存方法被放开了,存1存2都有可能再次做存操作,但是,不管谁做存都做不了,要等到取做完才能做存,即会有两个存线程进入等待状态,随后只有当取线程唤醒其中一个线程后才能进行存的操作,那么它又将唤醒一个线程,那么到底是唤醒存1还是存2呢?先不管,假设唤醒了存1,那存1又该唤醒谁呢?如果唤醒的是存2呢?那么取线程也就只能睡着,即下一个存线程无法解放,两个存线程就只能一直等待着,三个进入死锁。

猜你喜欢

转载自blog.csdn.net/qq_40826106/article/details/82761894