简体   繁体   中英

Threads not running concurrently

I hope this is not a repeat question, but I have looked at all the answers in other questions and none have satisfied my problem.

I have a program that has solves the Dining Philosopher's problem, and when I run the program, the threads wait until the next one is done before running another. This causes the thread's output to look like:

Philosopher 1 is EATING.
Philosopher 1 is THINKING.
Philosopher 5 is EATING.
Philosopher 5 is THINKING.
Philosopher 3 is EATING.
Philosopher 3 is THINKING.

... and so on. The expected output doesn't have an order. The threads should run concurrently. Here is my code, all of it is in here, with the interface just specifying the size of DINERS (5) and the State._______ is an enumeration with 3 states: State.HUNGRY, State.THINKING, and State.EATING.

import java.lang.Runnable;                                                      
import java.util.concurrent.locks.*;                                            
import java.util.Random;                                                        
import java.lang.Thread;                                                        
import java.util.concurrent.TimeUnit;                                           
/**                                                                             
 * This class handles the Philosophers, I hope they are hungry.                 
 *                                       
 * @version 4-20-15                                                             
 */                                                                             
public class Diner implements Runnable, PhilosopherInterface {                  

/** The lock used to control Thread access */                               
private final ReentrantLock lock;                                           
/** The state that the Philosopher is in (ex: Eating, Thinking etc.) */     
private State current;                                                      
/** The random number used to generate time sleeping */                     
private Random timeGenerator;                                               
/** The maximum time a thread can sleep */                                  
private final int maxTimeToSleep = 5000;                                    
/** The minimum time a thread can sleep (1ms) */                            
private final int minTimeToSleep = 1;                                       
private int philNum;                                                        
private int philIndex;                                                      
private Condition[] condition;                                              
private State[] states;                                                     

public Diner(ReentrantLock lock, int philNumber, Condition[] condition, State[] states)

    philNum = philNumber;                                                   
    philIndex = philNum - 1;                                                
    current = states[philNumber-1];                                         
    timeGenerator = new Random();                                           
    this.lock = lock;                                                       
    this.condition = condition;                                             
    this.condition[philIndex] = lock.newCondition();                        
    this.states = states;                                                   
    states[philIndex] = State.THINKING;                                     


}                                                                           

@Override                                                                   
public void takeChopsticks() {                                              

    states[philIndex] = State.HUNGRY;                                       
    lock.lock();                                                            
    try{                                                                    
        int left = philIndex-1;                                             
        int right = philIndex+1;                                            
        if(philNum == DINERS) right = 0;                                    
        if(philNum == 1) left = DINERS - 1;
test(left, philIndex, right);                                       
        if(states[philIndex] != State.EATING) {                             
            condition[philIndex].await();                                   
        }                                                                   
    }catch(InterruptedException e){}                                        

}                                                                           

@Override                                                                   
public void replaceChopsticks() {                                           
    try{                                                                    
    states[philIndex] = State.THINKING;                                     
    int left = philIndex-1;                                                 
    int right = philIndex+1;                                                
    if(philNum == DINERS) right = 0;                                        
    if(philNum == 1) left = DINERS - 1;                                     
    int leftOfLeft = left-1;                                                
    int rightOfRight = right+1;                                             
    if(left == 0) leftOfLeft = DINERS-1;                                    
    test(leftOfLeft, left, philIndex);                                      
    if(right == DINERS-1) rightOfRight = 0;                                 
    test(philIndex, right, rightOfRight);                                   
    }finally{ lock.unlock(); }                                              
    //states[philIndex] = State.THINKING;                                   
    //condition[left].signal();                                             
    //condition[right].signal();                                            
}                                                                           



public void think() {
System.out.println("Philosopher " + philNum + " is " + State.THINKING + ".");
    int timeToSleep = timeGenerator.nextInt(maxTimeToSleep) + minTimeToSleep;
    try {                                                                   
        Thread.sleep(500);                                                  
    }catch(InterruptedException e) {}                                       
}                                                                           

public void eat() {                                                         

        System.out.println("Philosopher " + philNum + " is " + State.EATING + ".");
    int timeToSleep = timeGenerator.nextInt(maxTimeToSleep) + minTimeToSleep;
    try {                                                                   
        Thread.sleep(500);                                                  
    }catch(InterruptedException e){}                                        
}                                                                           

@Override                                                                   
public void run() {                                                         

    while(true) {                                                           

        think();                                                            
        takeChopsticks();                                                   
        eat();                                                              
        replaceChopsticks();                                                
    }                                                                       
}                                                                           

public State getState() {                                                   
    return current;                                                         
}                                                                           

private void test(int left, int current, int right) {                       
    if(states[left] != State.EATING && states[current] == State.HUNGRY      
             && states[right] != State.EATING) {                            
        states[current] = State.EATING;                                     
        condition[current].signal();                                        
    }                                                                       
}                                                                           
}                                                                                     

Why are the treads not running concurrently? Thanks for the help! EDIT: To run it, there is a driver that is this:

public class Lunch {                                                            

public static void main(String[] args) {                                    

    ReentrantLock lock = new ReentrantLock();                               
    Thread[] diners = new Thread[PhilosopherInterface.DINERS];              
    Condition[] table = new Condition[PhilosopherInterface.DINERS];         
    State[] states = new State[PhilosopherInterface.DINERS];                
    for(int i=0; i<PhilosopherInterface.DINERS; i++) {                      
        states[i] = State.THINKING;                                         
    }                                                                       


    for(int i=0; i<PhilosopherInterface.DINERS; i++) {                      
        Diner diner = new Diner(lock, i+1, table, states);                  
        diners[i] = new Thread(diner);                                      
        diners[i].start();                                                  

    }                                                                       



}                                                                           

}                                        

EDIT2: Figured out the problem, Answer below.

Telling your threads to wait is not forcing them to work concurrently. If a thread needs to follow several steps before another one activates, then these methods(steps) should be synchronized.

I only locked once at the beginning of takeChopsticks() and unlocked at the end of replaceChopsticks(), forcing the thread to do everything before unlocking.

I used the lock() and unlock() methods at the start and finish of both takeChopsticks() and replaceChopsticks(), allowing it to run concurrently.

Try using an ExecutorService . Use ExecutorService.submit(Runnable) and ExecutorService.shutdown() which will wait until all the Runnable s have terminated and shutdown the ExecutorService .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM