Java基础之多线程中生产者和消费者问题

总结:

  • 同步锁的位置(synchronized的位置):方法、方法体、静态代码块都可以
  • 同步锁 锁住的对象:多个线程需要共用哪个类的资源,哪个类就是对象
  • wait,notify,notifyAll属于Object类,也就是每个对象都有wait,notify,notifyAll 的功能,但是使用 obj.wait,obj.notify,obj.notifyAll 的必须是同一个对象。因为多个线程只有使用相同的一个对象的时候,多线程之间才有互斥效果
  • wait,notify,notifyAll必须放在synchronized包裹的代码中执行,且只能被同步监听锁对象来调用

三个类:Producer、Consumer、Goods。生产者生产goods,消费者消耗goods,goods即是他们要竞争的公共资源。

第一种写法,写在方法上:

Producer:

public class Producer extends Thread{
    private Goods goods;

    public Producer(Goods goods){
        this.goods=goods;
    }

    public void run(){
        while (true){
            goods.product();
        }
    }
}

Cunsumer:

public class Consumer extends Thread{
    private Goods goods;

    public Consumer(Goods goods){
        this.goods=goods;
    }

    public void run(){
        while(true) {
            goods.consume();
        }
    }
}

Goods:

public class Goods {
    private int good;

    public Goods(int good) {
        this.good = good;
    }

    public synchronized void consume() { //消费
        while (good <= 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        --good;
        System.out.println(Thread.currentThread().getName()+"消耗了货物,还剩" + good);
        notifyAll();
    }

    public synchronized void product() { //生产
        while (good > 10) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        ++good;
        System.out.println(Thread.currentThread().getName()+"生产了货物,还剩" + good);
        notifyAll();
    }
}

Test:

public class Test {
    public static void main(String[] args) {
        Goods goods=new Goods(1);
        new Consumer(goods).start();
        new Consumer(goods).start();
        new Producer(goods).start();
        new Producer(goods).start();
    }
}

第二种写法,写在方法体里面:

生产者Producer:

public class Producer extends Thread{
    private Goods goods;

    public Producer(Goods goods){
        this.goods=goods;
    }

    public void run(){
        while (true){
            synchronized (goods){
                int good;
                while ((good=goods.getGood()) > 10) {
                    try {
                        goods.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                ++good;
                goods.setGood(good);
                System.out.println(Thread.currentThread().getName()+"生产了货物,还剩" + good);
                goods.notifyAll();
            }
        }
    }
}

消费者Consumer:

public class Consumer extends Thread{
    private Goods goods;

    public Consumer(Goods goods){
        this.goods=goods;
    }

    public void run(){
        while(true) {
            synchronized (goods){
                int good;
                while ((good=goods.getGood()) <= 0) {
                    try {
                        goods.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                --good;
                goods.setGood(good);
                System.out.println(Thread.currentThread().getName()+"消耗了货物,还剩" + good);
                goods.notifyAll();
            }
        }
    }
}

他们竞争的资源Goods:

public class Goods {
    private int good;

    public Goods(int good) {
        this.good = good;
    }

    public int getGood() {
        return good;
    }

    public void setGood(int good) {
        this.good = good;
    }

}

测试类Test:

public class Test {
    public static void main(String[] args) {
        Goods goods=new Goods(1);
        new Consumer(goods).start();
        new Consumer(goods).start();
        new Producer(goods).start();
        new Producer(goods).start();
    }
}

注意:
在这里插入图片描述在这里插入图片描述
第二种方法,在wait和notifyAll前面加了goods,如果不加会报错 IllegalMonitorStateException

  • 源码里面这样解释这个异常:
    在这里插入图片描述

而第一种方法不加不会报错,查看了一下第一种方法反编译的class文件,实际上调用wait和notifyAll的代码是这样的:
在这里插入图片描述在这里插入图片描述
为什么呢:

  • wait()、notify()和notifyAll()都是定义在Object类中,所以任意对象都有这三种方法,但是这三种方法只能被同步监听锁对象来调用
  • Java会在编译的时候给类里面的成员变量和方法,默认加上this。这样写两种方法wait和notifyAll的对象才是goods,如果第二种方法不加,实际上是调用的生产者和消费者的wait和notifyAll方法。对象都不一样了,Consumer.wait怎么能被Producer.notifyAll唤醒呢,再加上这里的同步监听锁对象是goods,那只能使用goods的wait和notifiAll方法,所以如果不加goods就会报错。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值