一、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条鱼