Так что я делаю программу для класса. Цель программы состоит в том, чтобы несколько человек съели фрукты из сумки. Плоды дают энергию, и энергия людей уменьшается каждую секунду. Проблема у меня в том, что каждый раз, когда плод съедают я делаю вывод, который выглядит следующим образом:Почему мой поток имеет одно и то же сообщение?
System.out.println("There are now " + fruitList.size() + " fruits left in the bag.");
Это должно, насколько я понимаю, выходной текущий размер моей ArrayList. То, что я смущен, состоит в том, что если два человека (инициализированные через два разных потока) едят примерно в одно и то же время, это должно показаться, например, сначала: «В сумке осталось 10 фруктов», а затем «Там теперь осталось 9 фруктов в сумке ». Проблема в том, что оба этих сообщения покажут, что осталось 10 фруктов.
Это метод в классе Person, который несет ответственность за это действие:
public void eat(Fruit fruit, ArrayList<Fruit> fruitList, MagicBag magicBag) {
lock.lock();
try {
while (getEnergy() > 20) {
newDeposit.await();
}
if(energy < 30 && energy > 20) {
System.out.println(this.getName() + " is getting hungry.");
} else {
System.out.println(this.getName() + " picked a " + fruitList.get(fruitList.size() - 1).getName() + " and started to eat...");
Thread.sleep(1000);
int fruitEnergy;
fruitEnergy = fruitList.get(fruitList.size() - 1).getEnergyValue();
fruitList.remove(fruitList.size() - 1);
if(energy > 100) {
energy = 100;
} else {
energy += fruitEnergy;
}
System.out.println(this.getName() + " ate a " + fruitList.get(fruitList.size() - 1).getName() + "!");
System.out.println("There are now " + fruitList.size() + " fruits left in the bag.");
magicBag.addFruitsToBag(fruitList, fruit);
newDeposit.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
И это то, что бег() делает в классе, который реализует Runnable, который работает под управлением выше код:
public void run() {
// TODO Auto-generated method stub
try {
while(running) {
if(fruitList.size() > 0) {
person.eat(fruit, fruitList, magicBag);
Thread.sleep(1000);
}
else {
kill();
}
}
} catch(InterruptedException e) {
e.printStackTrace();
} catch(IndexOutOfBoundsException ie) {
running = false;
} catch(NullPointerException ne) {
ne.printStackTrace();
}
}
Так что, если бы кто-нибудь мог мне помочь, это было бы здорово. Если вам нужно что-то еще, просто спросите.
Очень простое правило: если параллельный метод вызывает что-то вроде fruitlist.size() несколько раз, он делает это неправильно (потому что он может меняться между ними). Это не ваша проблема, а другая. В вашем случае вам просто нужно убедиться, что удаление будет первым, что вы делаете. И когда вы получаете доступ к списку (удалить/размер), вы должны синхронизировать его в течение этого короткого времени, поскольку список не является потокобезопасным. – eckes