2015-04-22 162 views
0

我希望這不是一個重複的問題,但我已經查看了其他問題中的所有答案,但都沒有滿足我的問題。線程不能同時運行

我有一個解決了Dining Philosopher問題的程序,當我運行程序時,線程會等到下一個完成後再運行另一個程序。這導致線程的輸出如下:

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

...等等。預期產出沒有訂單。線程應該同時運行。這裏是我的代碼,它全部在這裏,界面只是指定DINERS(5)和國家的大小._______是一個枚舉,包含3個狀態:State.HUNGRY,State.THINKING和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();           
    }                  
}                   
}                      

爲什麼踏板不能同時運行?謝謝您的幫助! 編輯:要運行它,有一個驅動程序是這樣的:

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:想通了這個問題,回答以下。

+0

我用驅動程序編輯原始帖子。 – user2751164

+1

必須是我認識的另一批哲學家,或者他們改變了他們的用餐習慣......我認識的那些人在湯匙和叉子上競爭,並試圖順序獲得兩種資源以便吃,這可能導致僵局時一個擁有代表叉的互斥體,另一個擁有代表勺的互斥體,每個互斥體都試圖獲得相應的另一個。 – BitTickler

+0

你的'think()'和'eat()'方法都會計算一個'timeToSleep',但是不要使用它。他們都睡了半秒鐘。那是故意的嗎? –

回答

3

告訴你的線程等待並不是強制它們同時工作。如果一個線程在另一個線程激活之前需要執行幾個步驟,那麼應該同步這些方法(步驟)。

+0

有沒有辦法做到這一點,而不使用同步?我寧願使用Java Condition Variables而不是使用它。 – user2751164

+0

我希望我能詳細闡述你的問題,但我的知識不是無限的。一個問題給你,爲什麼你不想使用同步?編輯:並使用java條件變量? – Josephus87

+0

@ user2751164如果您的線程必須以特定的順序__和___同時執行,那麼就沒有辦法不使用同步或某種其他形式的同步(障礙或鎖存器)。條件語句是針對單線程流的。 –

-1

嘗試使用ExecutorService。使用ExecutorService.submit(Runnable)ExecutorService.shutdown()將等待,直到所有Runnable s已終止並關閉ExecutorService

0

我只在takeChopsticks()的開始處鎖定一次,並在replaceChopsticks()的末尾解鎖,強制線程在解鎖之前完成所有操作。

我在takeChopsticks()和replaceChopsticks()的開始和結束處使用lock()和unlock()方法,允許它同時運行。