I am new to java concurrency and working with locks. I am trying to solve the dining problem and I don't have deadlocks yet only one thread gets actual runtime. Can anyone tell me what am I doing wrong?
class Philosopher implements Runnable {
private Random numGenerator = new Random();
private int id;
private ChineseStick minChopstick;
private ChineseStick maxChopstick;
public Philosopher (int id, ChineseStick leftChopstick, ChineseStick rightChopstick) {
this.id = id;
if(leftChopstick.getNumber() > rightChopstick.getNumber()){
this.minChopstick = rightChopstick;
this.maxChopstick = leftChopstick;
}
else{
this.minChopstick = leftChopstick;
this.maxChopstick = rightChopstick;
}
}
/**
* Repeatedly think, pick up chopsticks, eat and put down chopsticks
*/
public void run() {
try {
while (true) {
pickUpLeftChopstick();
pickUpRightChopstick();
eat();
putDownChopsticks();
think();
}
} catch (InterruptedException e) {
System.out.println("Philosopher " + id + " was interrupted.\n");
}
catch(Exception e){
System.out.println("Philosopher " + id + " raised exceptions.\n");
}
}
/**
* Lets a random amount of time pass to model thinking.
* @throws InterruptedException
*/
private void think() throws InterruptedException {
System.out.println("Philosopher " + id + " is thinking.\n");
System.out.flush();
Thread.sleep (numGenerator.nextInt(10));
}
/**
* Locks the left chopstick to signify that this philosopher is holding it
* @throws InterruptedException
*/
private void pickUpLeftChopstick() throws InterruptedException {
while(!minChopstick.lock.tryLock()){
synchronized(minChopstick.lock){
minChopstick.lock.wait();
}
}
minChopstick.lock.lock();
System.out.println("Philosopher " + id + " is holding " + this.minChopstick.getNumber() + " chopstick.\n");
System.out.flush();
}
/**
* Locks the right chopstick to signify that this philosopher is holding it
* @throws InterruptedException
*/
private void pickUpRightChopstick() throws InterruptedException {
while(!maxChopstick.lock.tryLock()){
synchronized(maxChopstick.lock){
maxChopstick.lock.wait();
}
}
maxChopstick.lock.lock();
System.out.println("Philosopher " + id + " is holding " + this.maxChopstick.getNumber() + " chopstick.\n");
System.out.flush();
}
/**
* Lets a random amount of time pass to model eating.
* @throws InterruptedException
*/
private void eat() throws InterruptedException {
System.out.println("Philosopher " + id + " is eating.\n");
System.out.flush();
Thread.sleep (numGenerator.nextInt(10));
}
/**
* Releases the locks on both chopsticks to model putting them down so the
* other philosophers can use them.
*/
private void putDownChopsticks() {
minChopstick.lock.unlock();
synchronized(minChopstick.lock){
minChopstick.lock.notifyAll();
}
maxChopstick.lock.unlock();
synchronized(maxChopstick.lock){
maxChopstick.lock.notifyAll();
}
}
}
The stick class:
public class ChineseStick {
public ChineseStick(int number){
this.lock = new ReentrantLock();
this.number = number;
}
public Lock lock;
private int number;
public int getNumber(){
return this.number;
}
}
The Main is very simple:
public static void main (String[] args) {
// Model each chopstick with a lock
//Lock[] chopsticks = new ReentrantLock[NUM_PHILOSOPHERS];
ChineseStick[] sticks = new ChineseStick[NUM_PHILOSOPHERS];
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
sticks[i] = new ChineseStick(i);
}
// Create the philosophers and start each running in its own thread.
Philosopher[] philosophers = new Philosopher[NUM_PHILOSOPHERS];
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
philosophers[i] = new Philosopher(i, sticks[i], sticks[(i+1)%NUM_PHILOSOPHERS]);
new Thread(philosophers[i]).start();
}
}
You are trying to get the lock inside this loop: while(!maxChopstick.lock.tryLock()) …
This loop ends when tryLock
returns true
which implies that you have the lock . But you invoke lock
additionally after the loop thus have locked twice . So a single unlock
invocation does not release the lock then.
But your code contains other problems as well. You are swapping the left and right sticks in the Philosopher
's constructor based on the stick numbers which makes no sense as the main
method already provides the stick instances correctly for a round table. It is correct for the last person to have a left item with a higher number than the right item as you wrap-around the array combining the last item with the first one. Swapping them then breaks what was initially correct.
Once you have fixed that, you will have the same problem as explained in this answer : If all eaters grab the left stick first, you can reach the situation that all eaters have locked their left stick and no one can proceed.
Additional coding style odds: you have a ChineseStick
class but instead of providing a grab
operation there, you implement it in the Philosopher
with duplicate code for left and right sticks. If ChineseStick
had a single pickUp()
method, the Philosopher
needed only invoke minChopstick.pickUp()
and maxChopstick.pickUp()
respectively rather than implementing two pickUp…Chopstick()
methods containing the same code.
And you are mixing up Lock
and synchronized
. This is a perfect way to create unmaintainable, confusing code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.