Java多线程(五)生产者、消费者案例

一、wait、notify

1、案例一【生产完再消费,消费完再生产

生产完再消费,消费完再生产:满足数量后才开始进行消费,消费完全部再进行生产

一只猫钓鱼,一次钓一条,放桶里,满五条后,拿回家。
另一只猫吃鱼,一次吃一条,吃完后,让钓鱼猫再去钓鱼 ,如此继续

(1)水桶:用来放鱼

/**
 * 水桶:用来放鱼
 */
public class Bucket {

    public static final int MAX_FISH_COUNT = 5;

    int fishCount;

    public int getFishCount() {
        return fishCount;
    }

    public void doPutFish() {
        fishCount++;
    }

    public void doRemoveFish() {
        if (fishCount > 0) {
            fishCount--;
        }
    }
}

(2)创建生产者和消费者

/**
 * 生产猫
 */
public class ProducerCat implements Runnable {

    private Bucket bucket;

    public ProducerCat(Bucket bucket) {
        this.bucket = bucket;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bucket) {
                if (bucket.getFishCount() >= Bucket.MAX_FISH_COUNT) {
                    System.out.println(Thread.currentThread().getName() + "桶里的鱼已经满了,可以拿桶回家了:" + bucket.getFishCount());
                    try {
                        System.out.println(Thread.currentThread().getName() + "【通知】其他猫准备吃鱼");
                        //先通知【等待池】:可以将随机一个线程放入【锁池】(准备获取锁);只有当前拥有锁的线程释放锁,才能被【锁池】中别的线程争抢
                        bucket.notify();

                        System.out.println(Thread.currentThread().getName() + "【等待】生产猫------进入等待:桶里已经满了");
                        //再释放锁
                        bucket.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    bucket.doPutFish();
                    System.out.println(Thread.currentThread().getName() + "【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有" + bucket.getFishCount() + "条鱼");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
/**
 * 消费猫
 */
public class ConsumerCat implements Runnable {

    private Bucket bucket;

    public ConsumerCat(Bucket bucket) {
        this.bucket = bucket;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bucket) {
                if (bucket.getFishCount() <= 0) {
                    System.out.println(Thread.currentThread().getName() + "桶里的鱼吃完了:" + bucket.getFishCount());
                    try {
                        System.out.println(Thread.currentThread().getName() + "【通知】钓鱼猫准备钓鱼");
                        //先通知【等待池】:可以将随机一个线程放入【锁池】(准备获取锁);只有当前拥有锁的线程释放锁,才能被【锁池】中别的线程争抢
                        bucket.notify();

                        System.out.println(Thread.currentThread().getName() + "【等待】消费猫------进入等待");
                        //再释放锁
                        bucket.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    bucket.doRemoveFish();
                    System.out.println(Thread.currentThread().getName() + "【吃鱼】消费猫------吃掉一条鱼,桶里还剩" + bucket.getFishCount() + "条鱼");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

(3)main方法测试

/**
 * 【生产完再消费,消费完再生产:满足数量后才开始进行消费,消费完全部再进行生产】
 * 一只猫钓鱼,一次钓一条,放桶里,满五条后,拿回家。
 * 另一只猫吃鱼,一次吃一条,吃完后,让钓鱼猫再去钓鱼 ,如此继续
 */
public class Demo {

    public static void main(String[] args) {
        Bucket bucket = new Bucket();
        new Thread(new ConsumerCat(bucket)).start();
        new Thread(new ProducerCat(bucket)).start();
    }
}

 (4)执行结果

Thread-0桶里的鱼吃完了:0
Thread-0【通知】钓鱼猫准备钓鱼
Thread-0【等待】消费猫------进入等待
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有1条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有2条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有3条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有4条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有5条鱼
Thread-1桶里的鱼已经满了,可以拿桶回家了:5
Thread-1【通知】其他猫准备吃鱼
Thread-1【等待】生产猫------进入等待:桶里已经满了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩4条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩3条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩2条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩1条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩0条鱼
Thread-0桶里的鱼吃完了:0
Thread-0【通知】钓鱼猫准备钓鱼
Thread-0【等待】消费猫------进入等待
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有1条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有2条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有3条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有4条鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有5条鱼
Thread-1桶里的鱼已经满了,可以拿桶回家了:5
Thread-1【通知】其他猫准备吃鱼
Thread-1【等待】生产猫------进入等待:桶里已经满了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩4条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩3条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩2条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩1条鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩0条鱼

2、案例二边生产边消费

【边生产边消费】生产者:只要不大于5就一直去生产;消费者:只要有就可以一直去消费

桶里最多放5条鱼
一只猫钓鱼,一次钓一条
放桶里
同时通知另一只猫吃鱼,一次吃一条
同时通知钓鱼猫再钓鱼 (只要桶里鱼不满足5条)
如此继续 

(1)水桶:用来放鱼

/**
 * 水桶:用来放鱼
 */
public class Bucket {

    public static final int MAX_FISH_COUNT = 5;

    int fishCount;

    public int getFishCount() {
        return fishCount;
    }

    public void doPutFish() {
        fishCount++;
    }

    public void doRemoveFish() {
        if (fishCount > 0) {
            fishCount--;
        }
    }
}

(2)创建生产者和消费者

/**
 * 生产猫
 */
public class ProducerCat implements Runnable {

    private Bucket bucket;

    public ProducerCat(Bucket bucket) {
        this.bucket = bucket;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bucket) {
                //桶里大于等于5条就满了,钓鱼猫停止钓鱼,通过wait进入等待池,并释放锁
                if (bucket.getFishCount() >= Bucket.MAX_FISH_COUNT) {
                    try {
                        System.out.println(Thread.currentThread().getName() + "【等待】生产猫------进入等待:桶里已经满了");
                        //释放锁
                        bucket.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //桶里小于5条就始终钓鱼,然后通知吃鱼猫
                try {
                    //继续钓鱼
                    bucket.doPutFish();
                    System.out.println(Thread.currentThread().getName() + "【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有" + bucket.getFishCount() + "条鱼");
                    Thread.sleep(1000);
                    //只要有鱼,吃鱼猫就可以吃鱼了
                    System.out.println(Thread.currentThread().getName() + "【通知】其他猫准备吃鱼");
                    //先通知【等待池】:可以将随机一个线程放入【锁池】(准备获取锁);只有当前拥有锁的线程释放锁,才能被【锁池】中别的线程争抢
                    bucket.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/**
 * 消费猫
 */
public class ConsumerCat implements Runnable {

    private Bucket bucket;

    public ConsumerCat(Bucket bucket) {
        this.bucket = bucket;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bucket) {
                //桶里没有鱼:吃鱼猫停止吃鱼,通过wait进入等待池,并释放锁
                if (bucket.getFishCount() <= 0) {
                    System.out.println(Thread.currentThread().getName() + "桶里的鱼吃完了:" + bucket.getFishCount());
                    try {
                        System.out.println(Thread.currentThread().getName() + "【等待】消费猫------进入等待");
                        //释放锁
                        bucket.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    //桶里有鱼就可以进行吃鱼
                    bucket.doRemoveFish();
                    System.out.println(Thread.currentThread().getName() + "【吃鱼】消费猫------吃掉一条鱼,桶里还剩" + bucket.getFishCount() + "条鱼");
                    Thread.sleep(2000);
                    if (bucket.getFishCount() < Bucket.MAX_FISH_COUNT) {
                        System.out.println(Thread.currentThread().getName() + "【通知】桶里不满,还剩" + bucket.getFishCount() + "条鱼,可以通知钓鱼猫钓鱼了");
                        //先通知【等待池】:可以将随机一个线程放入【锁池】(准备获取锁);只有当前拥有锁的线程释放锁,才能被【锁池】中别的线程争抢
                        bucket.notify();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(3)main方法测试

/**
 * 【边生产边消费:生产者:只要不大于5就一直去生产;消费者:只要有就可以一直去消费】
 * 桶里最多放5条鱼,
 * 一只猫钓鱼,一次钓一条
 * 放桶里
 * 同时通知另一只猫吃鱼,一次吃一条
 * 同时通知钓鱼猫再钓鱼 (只要桶里鱼不满足5条)
 * 如此继续
 */
public class Demo {

    public static void main(String[] args) {
        Bucket bucket = new Bucket();
        new Thread(new ConsumerCat(bucket)).start();
        new Thread(new ProducerCat(bucket)).start();
    }
}

 (4)执行结果

Thread-0桶里的鱼吃完了:0
Thread-0【等待】消费猫------进入等待
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有1条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩0条鱼
Thread-0【通知】桶里不满,还剩0条鱼,可以通知钓鱼猫钓鱼了
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有1条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩0条鱼
Thread-0【通知】桶里不满,还剩0条鱼,可以通知钓鱼猫钓鱼了
Thread-0桶里的鱼吃完了:0
Thread-0【等待】消费猫------进入等待
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有1条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有2条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有3条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩2条鱼
Thread-0【通知】桶里不满,还剩2条鱼,可以通知钓鱼猫钓鱼了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩1条鱼
Thread-0【通知】桶里不满,还剩1条鱼,可以通知钓鱼猫钓鱼了
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有2条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有3条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有4条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有5条鱼
Thread-1【通知】其他猫准备吃鱼
Thread-1【等待】生产猫------进入等待:桶里已经满了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩4条鱼
Thread-0【通知】桶里不满,还剩4条鱼,可以通知钓鱼猫钓鱼了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩3条鱼
Thread-0【通知】桶里不满,还剩3条鱼,可以通知钓鱼猫钓鱼了
Thread-0【吃鱼】消费猫------吃掉一条鱼,桶里还剩2条鱼
Thread-0【通知】桶里不满,还剩2条鱼,可以通知钓鱼猫钓鱼了
Thread-1【钓鱼】生产猫------钓鱼掉到一条鱼,桶里有3条鱼

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值