悠然自德 发表于 2009-2-24 10:37:46

Java解哲学家就餐问题

哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及一个避免死锁的解决方法。

    有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。

    哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。

    如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。这就会造成死锁了。。这是需要坚决杜绝的,正如操作系统的死锁问题。
                                                                                    
代码如下: import java.util.Random;
public class DiningPhils
{
public static void main(String[] args)
{
int n = 10;
if( n < 1)
{
   System.err.println( "DiningPils <# of philosophers>" );
   System.exit(-1);
}
DiningPhils self = new DiningPhils();
self.init(n);
}
public int getCount()
{
return n;
}
public void setChopstick( int i, boolean v)
{
chops[ i ] = v;
}
public boolean getChopstick( int i )
{
return chops;
}
private void init( final int N)
{
r = new Random();
n = ( N < 0 || N > maxPhils ) ? maxPhils : N;
chops = new boolean;
phils = new Philosopher;
initPhils();
dumpStatus();
}
private void initPhils()
{
for( int i = 0; i< n; i   )
{
   phils = new Philosopher( this, i );
   phils.setTimeSlice( generateTimeSlice());
   phils.setPriority( Thread.NORM_PRIORITY - 1);
/**哲学家进程降低一级,使所有哲学家进程
*全部初始化完毕前不会有哲学家进程抢占主线程*/
}
while( moreToStart() )
{
   int i = Math.abs( r.nextInt()) % n;
   if( !phils.isAlive())
   {
    System.out.println( " ### Philosopher "
      String.valueOf( i )   " started.");
    phils.start();
   }
}
System.out.println( "\nPhilosophers            Chopsticks"
      "\n(1 = eating, 0 = thinking)(1 = taken, 0 = free)");
}
public int generateTimeSlice()
{
int ts = Math.abs(r.nextInt()) %(maxEat   1);
if( ts == 0 )
   ts = minEat;
return ts;
}
public void dumpStatus()
{
for( int i = 0; i < n; i)
   System.out.print(phils.getEat() ? 1 : 0);
for( int i = n; i < maxPhils   4; i   )
   System.out.print(" ");
for( int i = 0; i < n; i)
   System.out.print(chops? 1:0);
System.out.println();
}
private boolean moreToStart()
{
for( int i = 0; i < phils.length; i   )
{
   if( !phils.isAlive())
    return true;
}
return false;
}
private int n;
private Philosopher[] phils;
private boolean[] chops;
private Random r;
private static final int maxPhils = 24;//最多哲学家数
private static final int maxEat = 4;   //最多进餐时间
private static final int minEat = 1;   //最少进餐时间
}
class Philosopher extends Thread
{
public Philosopher( DiningPhils HOST , int i )
{
host = HOST;
index = i;
}
public void setTimeSlice( int TS )
{
ts = TS;
}
public void setLeftChopstick( boolean flag )
{
host.setChopstick(index, flag);
}
public void setRightChopstick( boolean flag )
{
host.setChopstick((index   1)% host.getCount() , flag);
}
private void releaseChopsticks()
{
setLeftChopstick(false);
setRightChopstick(false);
}
public boolean chopsticksFree()
{
return !host.getChopstick(index) &&
!host.getChopstick((index 1)%host.getCount());
}
public void run()
{
while(true)
{
   grabChopsticks();
   eat();
   think();
}
}
private synchronized void grabChopsticks() /**临界区函数,确保哲学家在没有筷子或筷子不够时思考,满足条件后才就餐*/
{
while( !chopsticksFree())
{
   try
   {
    wait();
   }
   catch( InterruptedException e){}
}
takeChopsticks();
notifyAll();
}
private void takeChopsticks()
{
setLeftChopstick( true );
setRightChopstick( true );
setEat(true);
host.dumpStatus();
}
private void eat()
{
pause();
setEat( false );
releaseChopsticks();
}
private void think()
{
pause();
}
private void pause()
{
setTimeSlice( host.generateTimeSlice());
try
{
   sleep(ts*1000);
}
catch( InterruptedException e){}
}
private void setEat(boolean v)
{
isEating = v;
}
public boolean getEat()
{
return isEating;
}
private DiningPhils host;
private boolean isEating;
private int index;
private int ts;
}
页: [1]
查看完整版本: Java解哲学家就餐问题