8.线程通信的引入&&生产者与消费者

应用场景:生产者和消费者问题

假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费.

如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止

如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止

代码:

1.商品: 属性:品牌,名字

2.线程1:生产者

3.线程2:消费者

//商品类
public class Product {//商品类
    //品牌
    private String brand;

    //名字
    private String name;

    //setter,getter方法

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class ProducerThread extends Thread{//生产者线程
    //共享商品
    private Product p;

    public ProducerThread(Product p){
        this.p=p;
    }

    @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:生产次数
            if (i%2==0){
                //生产费列罗巧克力
                p.setBrand("费列罗");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                p.setName("巧克力");
            }else{
                p.setBrand("哈尔滨");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                p.setName("啤酒");
            }
            System.out.println("生产者生产了:" + p.getBrand() + "-----" + p.getName());
        }
    }
}
public class CustomerThread extends Thread {//消费者线程
    //共享商品
    private Product p;
    public CustomerThread(Product p){
        this.p = p;
    }

    @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:消费次数
            System.out.println("消费者消费了:" + p.getBrand() + "----" + p.getName());
        }
    }
}
public static void main(String[] args) {
        //共享商品
        Product p = new Product();

        //创建生产者和消费者线程
        ProducerThread pt = new ProducerThread(p);
        CustomerThread ct = new CustomerThread(p);

        pt.start();
        ct.start();
    }

运行效果

 出现问题:

1.生产者和消费者没有交替输出

2.打印数据错乱,没有加同步

解决问题:

1.同步代码块

public class ProducerThread extends Thread{//生产者线程
    //共享商品
    private Product p;//这个对象是共享的,所以锁这个

    public ProducerThread(Product p){
        this.p=p;
    }

    @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:生产次数
            synchronized(p){
                if (i%2==0){
                    //生产费列罗巧克力
                    p.setBrand("费列罗");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    p.setName("巧克力");
                }else{
                    p.setBrand("哈尔滨");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    p.setName("啤酒");
                }
            }
            System.out.println("生产者生产了:" + p.getBrand() + "-----" + p.getName());
        }
    }
}
public class CustomerThread extends Thread {
    //共享商品
    private Product p;
    public CustomerThread(Product p){
        this.p = p;
    }

    @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:消费次数
            synchronized(p){
                System.out.println("消费者消费了:" + p.getBrand() + "----" + p.getName());
            }
        }
    }
}

2.利用同步方法解决问题

//在商品类增加同步方法
//生产商品
    public synchronized void setProduct(String brand,String name){
        //生产费列罗巧克力
        this.setBrand(brand);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.setName(name);
        System.out.println("生产者生产了:" + this.getBrand() + "-----" + this.getName());
    }

    //消费商品
    public synchronized void getProduct(){
        System.out.println("消费者消费了:" + this.getBrand() + "----" + this.getName());
    }
//在生产者类重写run()修改
 @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:生产次数
            if (i%2==0)
                p.setProduct("费列罗","巧克力");
            else
                p.setProduct("哈尔冰","啤酒");
        }
    }
//消费者类重写run方法中修改
 @Override
    public void run() {
        for (int i=1;i<=10;i++){//i:消费次数
            p.getProduct();
        }
    }

还是留下问题,没有交替输出,使用线程通信完善代码

//商品类
public class Product {//商品类
    //品牌
    private String brand;

    //名字
    private String name;

    boolean flag=false;//引入一个灯,true 为有产品 false为没产品
    //默认情况没有产品 让生产者先生产 然后消费者再消费

    //setter,getter方法

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //生产商品
    public synchronized void setProduct(String brand,String name){
        if(flag == true){//证明有商品,生产者不生产,等着消费者消费
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //下面flag为false,生产
        //生产费列罗巧克力
        this.setBrand(brand);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.setName(name);
        System.out.println("生产者生产了:" + this.getBrand() + "-----" + this.getName());

        //生产完后
        flag=true;
        //告诉消费者来消费
        notify();
    }

    //消费商品
    public synchronized void getProduct(){
        if (!flag) {//flag==false没有商品 ,等待生产者生产
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费者消费了:" + this.getBrand() + "----" + this.getName());
        //消费完
        flag=false;
        //通知生产者生产
        notify();
    }
}

这样生产者与消费者交替输出

在Java对象中,有两种池

锁池------->synchronized

等待池------->wait(),notify(),notifyAll()

如果一个线程调用了某个对象的wait()方法,那么该线程进入到该对象的等待池中(并且已经将锁释放),如果未来的某一时间,另外一个线程调用了相同对象的notify()方法或者notifyAll方法,那么该等待池中的线程就会被唤起,然后进入到对象的锁池里面去获得该对象的锁

如果获得锁成功后,那么该线程就会沿着wait方法之后的路径继续执行,注意是沿着wait方法之后

注意:

        wait方法和notify方法 是必须在同步代码块或者同步方法中生效(因为在同步的基础上进行线程的通信才是有效的)

        sleep和wait的区别:sleep进入阻塞状态没有释放锁,wait进入阻塞状态但是同时释放了锁

线程生命周期完整图

​​​​​​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值