【发布时间】:2021-12-08 20:27:38
【问题描述】:
我有一个练习,我有一个盛宴,其中来自 N = 10 人的人一次从锅中吃 1 份。锅的最大份量 M = 5。还有一个厨师在锅空了的时候给锅填满。servingsAvailable = 0。在填满的过程中人不能吃东西。我必须同步线程,只从 Pot 类中更改方法 fill 和 getServings(这些方法一开始是空的)。
你能告诉我这段代码我做错了什么吗?总量应为 1000,但总是更少。我实现了锅装满然后 5 人吃,然后是装满等但吃的份数不一致的情况。
人物类
public class Person extends Thread { // Reprezentuje tubylca
Pot pot;
int servingsConsumed = 0;
public Person(String name, Pot pot) {
super(name);
this.pot = pot;
}
@Override
public void run() {
try {
for (int i = 0; i < 100; ++i) {
pot.getServing(this.getName());
++servingsConsumed;
Thread.yield();
}
} catch(InterruptedException e) {
return ;
}
}
}
烹饪课
public class Cook extends Thread { // Reprezentuje kucharza
Pot pot;
public Cook(Pot pot) {
this.pot = pot;
setDaemon(true);
}
@Override
public void run() {
try {
while(!isInterrupted()) {
pot.fill();
}
} catch(InterruptedException e) {
return ;
}
}
}
锅类
import java.util.concurrent.Semaphore;
public class Pot {
static final int M = 5; // Pojemność kotła
private Semaphore emptyPot = new Semaphore(1);
private Semaphore available = new Semaphore(0);
private int servingsAvailable = 0;
private int totalServedCount = 0;
private synchronized void insertServings(int value) {
servingsAvailable = value;
}
private synchronized int removeServing() {
--servingsAvailable;
++totalServedCount;
return servingsAvailable;
}
public int getTotalServedCount() {
return totalServedCount;
}
public void getServing(String nameOfPerson) throws InterruptedException {
available.acquire();
if (servingsAvailable != 0) {
removeServing();
System.out.println(nameOfPerson + " ate 1 portion from pot");
}
available.release();
}
public void fill() throws InterruptedException {
available.acquire();
if (servingsAvailable == 0) {
insertServings(M);
System.out.println("Fill the pot with M = " + M);
}
available.release();
}
}
宴会班(主)
public class Feast {
public static void main(String[] args) throws InterruptedException {
Pot pot = new Pot();
Cook cook = new Cook(pot);
final int N = 10;
Person[] people = new Person[N];
for (int i = 0; i < people.length; ++i) {
people[i] = new Person("Person " + i, pot);
}
cook.start();
for (Thread t : people) {
t.start();
}
for (Thread t : people) {
t.join();
}
cook.interrupt();
System.out.printf("Total served: %d.\n", pot.getTotalServedCount());
for (Person p : people) {
System.out.printf("[%s] Ate %d servings.\n", p.getName(), p.servingsConsumed);
}
System.out.println("Finishing simulation.");
}
}
【问题讨论】:
-
totalServedCount仅在servingsAvailable != 0时递增。 -
但是
servingsConsumed无论如何都会递增。 -
在
Pot中,您的一些方法是synchronized,而有些则不是。这是行不通的,因为现在您使用两个不同的锁来保护相同的数据。 -
在
getTotalServedCount()的情况下,您根本没有使用任何锁,这是错误的。 Java要求你保护读写,否则同步无效。 -
@shmosel 在 n - 1 加入后。
Cook线程尚未加入。通常,将责任分散到多个类是一个糟糕的设计。它导致了我们在这里遇到的错误……以及大量其他错误。
标签: java concurrency