分类:
2008-10-16 19:25:09
哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及一个避免死锁的解决方法。
有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。
哲学家有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[i]; } private void init( final int N) { r = new Random(); n = ( N < 0 || N > maxPhils ) ? maxPhils : N; chops = new boolean[n]; phils = new Philosopher[n]; initPhils(); dumpStatus(); } private void initPhils() { for( int i = 0; i< n; i++ ) { phils[i] = new Philosopher( this, i ); phils[i].setTimeSlice( generateTimeSlice()); phils[i].setPriority( Thread.NORM_PRIORITY - 1); /**哲学家进程降低一级,使所有哲学家进程 *全部初始化完毕前不会有哲学家进程抢占主线程*/ } while( moreToStart() ) { int i = Math.abs( r.nextInt()) % n; if( !phils[i].isAlive()) { System.out.println( " ### Philosopher " + String.valueOf( i ) + " started."); phils[i].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[i].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[i]? 1:0); System.out.println(); } private boolean moreToStart() { for( int i = 0; i < phils.length; i++ ) { if( !phils[i].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; }