我是Java线程的新手。尝试使用Java的同步概念来执行死锁机制。这有一些问题。我想知道如何改进我的代码。 我的目标是避免死锁。
package threading;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DiningPhilospherProblem {
public static void main(String[] args)
{
Chopstick cs[] = new Chopstick [5];
for(int i=0;i<5;i++)
{
cs[i] = new Chopstick();
}
new Thread(new Philospher("One", cs[4],cs[0]) ).start();
new Thread(new Philospher("Two", cs[0],cs[1]) ).start();
new Thread(new Philospher("Three", cs[1],cs[2]) ).start();
new Thread(new Philospher("Four", cs[2],cs[3]) ).start();
new Thread(new Philospher("Five", cs[3],cs[4]) ).start();
}
}
class Philospher implements Runnable
{
private static final int EATING_TIME = 8000;
private static final int THINKING_TIME = 10000;
public enum State {
EATING, THINKING, WAITING
}
Chopstick left, right;
String name;
State state;
public Philospher(String name, Chopstick left,Chopstick right)
{
System.out.println(" Philospher " + name + " is ready");
this.name = name;
this.left =left;
this.right = right;
}
public void run()
{
for(int i =0; i< 10;i++){
eat();
}
System.out.println("Succesfully finished: " +name);
}
public void eat() // EDITED THIS FUNCTION
{
synchronized(left){
try{
while(right.isBeingUsed()){
System.out.println("Philospher " + name + " : is waiting");
setPhilosopherState(Philospher.State.WAITING);
left.wait();
}
synchronized(right)
{
left.setChopStickUsed(true);
right.setChopStickUsed(true);
System.out.println("Philospher " + name + " : is eaitng");
setPhilosopherState(Philospher.State.EATING);
Thread.sleep(EATING_TIME);
}
}
catch(InterruptedException e){}
finally
{
left.setChopStickUsed(false);
right.setChopStickUsed(false);
left.notify();
}
}
think();
}
public void think()
{
System.out.println("Philospher " + name + " : is thinking");
try
{
setPhilosopherState(State.THINKING);
Thread.sleep(THINKING_TIME);
}
catch (InterruptedException ex) {
Logger.getLogger(Philospher.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void setPhilosopherState(State state){
this.state = state;
System.out.println("Setting state : "+ state +", "+ name+";");
}
}
class Chopstick
{
boolean state_chopstick;
public synchronized void setChopStickUsed(boolean value)
{
state_chopstick = value;
}
public synchronized boolean isBeingUsed ()
{
return state_chopstick;
}
}
已编辑: eat()
方法请查看
答案 0 :(得分:1)
除了assylias对你的直接问题的回答,这里有一些关于改进逻辑的建议:
在检查left.isBeingUsed()
和left.setChopStickUsed(true);
之间,其他人可能已经抓住了筷子(这称为检查时间与使用时间的问题)。为了确保不会发生这种情况,您需要使用适当的机制来仅允许一位哲学家访问筷子对象并执行检查+抓取 atomicalliy ,例如用
boolean isEating = false;
if (left.grab()) {
if (right grab) {
// managed to grab both chopsticks
isEating = true;
} else {
// only grabbed the left one
left.release();
}
} else {
// could not grab the left one
}
if (isEating) {
// TODO: chew, swallow
left.release();
right.release();
} else {
// contemplate the cruelty of life
think();
}
其中Chopstick
具有以下方法:
public synchronized boolean grab()
{
if (state_chopstick) {
// already in use
return false;
}
_state_chopstick = true;
return true; // managed to grab it
}
public synchronized void release()
{
state_chopstick = false;
}
我的想法是grab()
检查筷子是否正在使用并且如果同时 ,则抓取它(这样可以避免时间 - 检查/使用时间问题)
注意:上述实现可能会导致 live-lock ,所有哲学家同时抓住左筷子,然后找到正确的筷子,重新使用左,思考,重复;因此从不吃东西。要解决这个问题,您可以动态决定(例如随机)哪个分叉首先抓取
答案 1 :(得分:0)
您获得了IllegalMonitorException
,因为wait
中的eat
没有对对象(this
)进行锁定。你应该看一下javadoc。
此外,您不会致电notify
或notifyAll
,因此您将永远等待。
你可能想要think
而不是wait
?