2016-04-29 77 views
1

这是哲学家就餐问题的又一实施,这是家庭作业的问题,我将在这里展示我迄今为止尝试:另一个哲学家就餐并发问题

/** 
* DPServer.java 
* <p> 
* This class implements the methods called by the philosophers 
*/ 
package cc; 

import java.util.Random; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class DPServer { 

    private static Lock chopstick[] = new Lock[5]; // Create chopstick locks 
    private static Lock mutex = new ReentrantLock(true); 

    private static int MAX_EAT_TIME = 5000; // maximum eating time in milliseconds 
    private static int MAX_THINK_TIME = 5000; // maximum thinking time in milliseconds 
    private static Random r = new Random(0); 


    // default constructor for DPServer class 
    public DPServer() { 
     for (int i = 0; i < 5; i++) { 
      chopstick[i] = new ReentrantLock(true); 
     } // end for 

    } // end DPServer default constructor 


    // called by a philosopher when they wish to eat 
    public void takeChopsticks(int philosopherNumber) { 
     // acquire chopstick[philosopherNumber] and chopstick[(philosopherNumber + 1) mod 5] 
     System.out.println("Acquiring chopstick[" + philosopherNumber + "] and chopstick[" + ((philosopherNumber + 1) % 5) + "]"); 
     chopstick[philosopherNumber].lock(); 
     chopstick[(philosopherNumber + 1) % 5].lock(); 
     // eat for a random number of milliseconds 
     int eatTime = r.nextInt(MAX_EAT_TIME); 
     System.out.println("Philosopher " + philosopherNumber + " is eating for " + eatTime + " milliseconds"); 
     try { 
      Thread.sleep(eatTime); 
     } catch (InterruptedException ex) { 
      System.out.println("Philosopher " + philosopherNumber + " eatTime sleep was interrupted"); 
     } 

    } // end takeChopsticks 


    // called by a philosopher when they are finished eating 
    public void returnChopsticks(int philosopherNumber) { 
     // release chopstick[philosopherNumber] and chopstick[(philosopherNumber + 1) mod 5] 
     System.out.println("Releasing chopstick[" + philosopherNumber + "] and chopstick[" + ((philosopherNumber + 1) % 5) + "]"); 
     chopstick[(philosopherNumber + 1) % 5].unlock(); 
     chopstick[philosopherNumber].unlock(); 

     // think for a random number of milliseconds 
     int thinkTime = r.nextInt(MAX_THINK_TIME); 
     System.out.println("Philosopher " + philosopherNumber + " is thinking for " + thinkTime + " milliseconds"); 
     try { 
      Thread.sleep(thinkTime); 
     } catch (InterruptedException ex) { 
      System.out.println("Philosopher " + philosopherNumber + " thinkTime sleep was interrupted"); 
     } 
    } 
} 


// implementation of the Dining Philosopher class 
package cc; 

public class DPhilosopher { 
    private int dpNum; 
    private DPServer dpServ; 

    // value constructor for the DPhilosopher class 
    public DPhilosopher(int num, DPServer d) { 
     dpNum = num; 
     dpServ = d; 
    } // end DPhilosopher value constructor 


    public void DPEatThink() { 
     while (true) { 
      // get ready to eat 
      System.out.println("Philosopher " + dpNum + " is getting ready to eat"); 
      dpServ.takeChopsticks(dpNum); 

      // finish eating 
      System.out.println("Philosopher " + dpNum + " is finished eating"); 
      dpServ.returnChopsticks(dpNum); 

     } 

    } 

    public static void main(String[] args) { 
     DPServer dps = new DPServer(); 
     DPhilosopher dp[] = new DPhilosopher[5]; 
     Thread dpThread[] = new Thread[5]; 

     // Create and launch the DPhilosopher threads 
     for (int i = 0; i < 5; i++) { 
      dp[i] = new DPhilosopher(i, dps); 
      final int finalI = i; 
      dpThread[i] = new Thread(new Runnable() { 
       @Override 
       public void run() { 
        dp[finalI].DPEatThink(); 
       } 
      }); 
      dpThread[i].start(); 
     } 

    } // end main 
} 

大部分代码给出了准备,除了takeChopsticks()而需要改变returnChopsticks()方法和我所做的就是将这样的:

chopstick[(philosopherNumber + 1) % 5].lock(); 
chopstick[philosopherNumber].lock(); 

chopstick[(philosopherNumber + 1) % 5].unlock(); 
chopstick[philosopherNumber].unlock(); 

我知道这不是线程安全的,并且这个link也保证它。真正神话的是老师希望我们用DPServer#mutex锁来解决这个问题,我可以锁住/解锁takeChopsticks()returnChopsticks()中的互斥锁,锁定和解锁2把锁(chopstick [philosopherNumber] .lock(); chopstick [(philosopherNumber + 1 )%5] .lock();),但这会造成死锁。

我只是没有看到如何解决这个只使用一个互斥体ReentrantLock。

任何人都可以帮助我吗?

在此先感谢。

+1

我不确定我的理解。为什么你需要锁定解锁互斥锁的位置?通过在锁定代码周围放置一个锁,每次只有一位哲学家可以捡起筷子。如果其中一根筷子不可用,则不希望锁定防止邻居哲学家放下筷子。 –

+0

@KyleA当我说放置锁定时,我的意思是mutex.loc();逻辑(),mutex.unlock();这是对的,这没有多大意义,但我被给了这个模板,并以某种方式与这个互斥体(ReentrantLock实例)将解决这个问题。 – user3143318

+0

是的,我的意思是一把锁可以绕过锁定逻辑,所以'锁;拾起筷子1;拾取筷子2;解锁'。这样你就无法解决僵局,因为只有一个哲学家可以在任何时候拿起筷子。 –

回答

1

如果你把周围获取锁,这样的锁:

// called by a philosopher when they wish to eat 
public void takeChopsticks(int philosopherNumber) { 
    // acquire chopstick[philosopherNumber] and chopstick[(philosopherNumber + 1) mod 5] 
    System.out.println("Acquiring chopstick[" + philosopherNumber + "] and chopstick[" + ((philosopherNumber + 1) % 5) + "]"); 

    lockLock.lock(); 
    chopstick[philosopherNumber].lock(); 
    chopstick[(philosopherNumber + 1) % 5].lock(); 
    lockLock.unlock(); 

    // eat for a random number of milliseconds 
    int eatTime = r.nextInt(MAX_EAT_TIME); 
    System.out.println("Philosopher " + philosopherNumber + " is eating for " + eatTime + " milliseconds"); 
    try { 
     Thread.sleep(eatTime); 
    } catch (InterruptedException ex) { 
     System.out.println("Philosopher " + philosopherNumber + " eatTime sleep was interrupted"); 
    } 

} // end takeChopsticks 

那么只有一个哲学家可以在一次拿起筷子的过程,但一切功能照常工作。

另一种方法是更改​​筷子的索引,以便奇数哲学家总是从拿起左筷子开始,而偶数哲学家总是先拿起右筷子开始。由于这是一项家庭作业,我将留下如何做这些练习的细节(实际上并不难,因为声明很容易)。

+0

我们不想为returnChopsticks做同样的机制吗? – user3143318

+1

为什么?你能想到这个程序中的一个场景,不控制筷子如何放下可能会导致僵局吗? –

+0

我不能,这是有些问题,我们是否真的需要同步放筷子。把它放在那里是没有意义的。 – user3143318