我已经等待并通知了一个抽象蛋糕店的示例程序。有一个角色蛋糕机用于生产蛋糕和一个带角色服务员的线程用于送蛋糕。我的期望是每次CakeMachine
课程完成制作蛋糕时它会向Waiter
课程发送通知。当我运行一个生产3个蛋糕的程序时,结果表明只交付了一个蛋糕。这是我的代码:
用于创建蛋糕对象的Cake
类:
class Cake {
private int weight;
private String color;
public Cake(int weight, String color) {
this.weight = weight;
this.color = color;
}
public String toString(){
return "The cake is in " + color +" and is " + weight + " gram ";
}
}
生产蛋糕的CakeMachine
类:
class CakeMachine implements Runnable{
private List<Cake> listCake;
CakeMachine(List<Cake> listCake) {
this.listCake = listCake;
}
public void makeCake() {
int weight = new Random().nextInt(20);
Cake cake = new Cake(weight, "color code is " + weight );
listCake.add(cake);
System.out.println("cake has been cooked ");
listCake.notify();
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
synchronized (listCake) {
makeCake();
}
}
}
}
提供蛋糕的Waiter
课程:
class Waiter implements Runnable {
private List<Cake> listCake;
Waiter(List<Cake> listCake) {
this.listCake = listCake;
}
public void delivery() {
System.out.println("Waiter is waiting for the cake ");
try {
listCake.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
Cake cake = listCake.get(listCake.size() - 1);
System.out.println(cake.toString() + "has been delivered to customers ");
}
@Override
public void run() {
for (int i = 0; i < 3; i++)
{
synchronized (listCake) {
delivery();
}
}
}
}
主要课程:
public class WaitAndNotify {
public static List<Cake> listCake = new ArrayList<>();
public static void main(String[] args) {
Thread waiter = new Thread(new Waiter(listCake));
Thread cakeMachine = new Thread(new CakeMachine(listCake));
waiter.start();
cakeMachine.start();
}
}
运行程序时的结果是:
Waiter is waiting for the cake
cake has been cooked
cake has been cooked
cake has been cooked
The cake is in color code is 18 and is 18 gram has been delivered to customers
Waiter is waiting for the cake
请帮助我了解这种情况。
答案 0 :(得分:2)
两个要点:
您无法控制何时运行的线程。
notify无效。你的服务员停止等待,蛋糕制作可以自由进行,并在服务员再次获得显示器之前完成。
在您的示例中,调度程序决定首先运行服务员的一次迭代,然后运行所有3次蛋糕制作迭代,然后在完成所有蛋糕后运行接下来的两次等待迭代。您可以引入标志来指示何时准备好蛋糕以及服务员何时等待,并且在服务员出现之前让蛋糕制作延迟通知,但尝试让线程以锁步方式执行确实是错误的,它会失败将活动分成自己的主题的目的。
添加条件标志后,交付方式如下所示:
public void delivery() {
System.out.println("Waiter is waiting for the cake ");
waiterInPosition = true;
try {
while (!(cakeQueued)) {
listCake.wait();
}
waiterInPosition = false;
cakeQueued = false;
Cake cake = listCake.get(listCake.size() - 1);
System.out.println(cake.toString()
+ "has been delivered to customers ");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore interrupt flag
}
}
但这是一个玩具的例子,它非常尴尬。将此作为生产者 - 消费者问题进行建模更为自然,蛋糕制造商将蛋糕添加到队列中,服务员将蛋糕从队列中取出。您可以尝试创建自己的阻塞队列,您的队列方法可以处理等待和通知 - 让数据结构处理同步和阻塞比让工作人员执行任务更自然。这将教你如何使用wait和notify作为当前的例子,同时更能代表真实的并发模式。
Oracle tutorial on guarded blocks包含一个阻塞队列示例,关于在带有条件变量的循环中等待的建议是必不可少的,请阅读它。
答案 1 :(得分:1)
这可以通过典型的生产者消费者问题来解决
蛋糕类:
class Cake {
private int weight;
private String color;
public Cake(int weight, String color) {
this.weight = weight;
this.color = color;
}
public String toString() {
return "The cake is in " + color + " and is " + weight + " gram ";
}
}
CakeMachine既是生产者又是消费者,它同时具有交付蛋糕和蛋糕功能
class CakeMachine {
private LinkedList<Cake> listCake = new LinkedList<Cake>();;
private Random random = new Random();
private static int LIMIT = 5;
public void makeCake() throws InterruptedException {
while (true) {
synchronized (this) {
while (listCake.size() == LIMIT) {
wait();
}
int weight = random.nextInt(20);
Cake cake = new Cake(weight, "color code is " + weight);
listCake.add(cake);
System.out.println("cake has been cooked ");
notify();
}
}
}
public void deliverCake() throws InterruptedException {
while (true) {
synchronized (this) {
Thread.sleep(random.nextInt(1000)); // on average 500 ms
while (listCake.size() == 0) {
System.out.println("Waiter is waiting for the cake ");
wait();
}
Cake cake = listCake.removeFirst();
System.out.println(cake.toString() + "has been delivered to customers ");
notify();
}
}
}
}
现在是最终的主要课程
public class CakeThreading {
public static void main(String[] args) {
final CakeMachine cm = new CakeMachine();
Thread cakeproducer = new Thread(new Runnable() {
@Override
public void run() {
try {
cm.makeCake();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread waiter = new Thread(new Runnable() {
@Override
public void run() {
try {
cm.deliverCake();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
cakeproducer.start();
waiter.start();
try {
cakeproducer.join();
waiter.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这将产生如下输出:
cake has been cooked
cake has been cooked
The cake is in color code is 2 and is 2 gram has been delivered to customers
The cake is in color code is 14 and is 14 gram has been delivered to customers
cake has been cooked
cake has been cooked
cake has been cooked
The cake is in color code is 13 and is 13 gram has been delivered to customers
The cake is in color code is 7 and is 7 gram has been delivered to customers
The cake is in color code is 19 and is 19 gram has been delivered to customers
Waiter is waiting for the cake
cake has been cooked
cake has been cooked
cake has been cooked
The cake is in color code is 12 and is 12 gram has been delivered to customers
The cake is in color code is 2 and is 2 gram has been delivered to customers
The cake is in color code is 2 and is 2 gram has been delivered to customers
cake has been cooked
cake has been cooked