⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diningphils.java

📁 哲学家进餐问题——Java语言实现 哲学家进餐问题是一个多线程运用的经典例子
💻 JAVA
字号:
import java.util.Random;

/*
 * 题目:正在进餐的哲学家类。<br>
 * 描述:主类,创建哲学家线程,并显示出当前哲学家和筷子的状态。
 * 
 * @author 石庆华
 */
public class DiningPhils
{
	/**
	 * 主函数,对线程进行初始化并运行。
	 * 
	 * @param args 这是一个字符串数组,用来接收控制台输入的参数。
	 */
 public static void main ( String [] args )
 {
	 final int n = 5;    //5名哲学家
	 DiningPhils self = new DiningPhils ( );   //创建自己的实例
	 self.init ( n );       //初始化操作
 }
 
 /**
  * 设置筷子的状态。<br>
  * ture 时为拿起,false 时为放下。
  * 
  * @param i 筷子数组的下标。
  * @param v boolean类型,ture 时为拿起,false 时为放下。
  */
 public void setChopstick( int i, boolean v )
 {
	 chops[ i ] = v;   
 }
 
 /**
  * 得到筷子的状态。
  * 
  * @param i 筷子数组中某个筷子的下标。
  * @return 返回boolean类型;ture 时为拿起,false 时为放下。
  */
 public boolean getChopstick( int i )
 {
	 return chops [ i ];
 }
 
 /**
  * 初始化操作。
  * @param N 哲学家数目,final类型。
  */
 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 ( );				//先是当前哲学家和筷子的状态
 }
 
 /**
  * 对哲学家数组初始化的方法。<p>
  * 对每一个哲学家进行初始化操作,并设置每一个哲学家的间隔时间(随机产生),最后每个
  * 哲学家进程降低一级,使所有哲学家进程全部初始化完毕前不会有哲学家进程抢占主线程。
  */
 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)" ); //状态提示
 }
 
 /**
  * 产生一个随机的时间间隔。
  * 
  * @return ts 随即产生的时间间隔(在maxEat和minEat之间)。当为零时,自动设置为最短进餐时间。
  */
 public int generateTimeSlice ( )
 {
	 int ts = Math.abs ( r.nextInt ( ) ) % ( maxEat + 1 );
	 if ( ts == 0 )
		 ts = minEat;
	 return ts;
 }
 
 /**
  * 显示当前哲学家进餐状态和筷子的使用情况。<p>
  * 1代表哲学家正在进餐反之正在思考,1代表筷子正在使用反之没有使用。
  */
 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 ( );
 }
 
 /**
  * 得到私有哲学家个数的公共方法。
  * 
  * @param n 哲学家的个数。
  * */
 public int getCount()
 {
	 return n;   //哲学家个数
 }
 
 /**
  * 判断是否还有没有启动的哲学家。
  * 
  * @return boolean 类型,<br>ture 表示还有没有启动的哲学家线程,<br>false 表示已经全部启动
  */
 private boolean moreToStart()
 {
	 for( int i = 0; i < phils.length; i++ )
	 {
		 if ( !phils [ i ].isAlive ( ) )    //若有没有在运行的线程
			 return true;					//返回true
  }
  return false;								//否则返回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;   //最少进餐时间
}

/**
 * 题目:哲学家类。<br>
 * 描述:继承了Thread线程类,覆盖了Thread 类的run()方法,可以完成think(),eat()等方法。
 * 
 * @author 石庆华
 *
 */
class Philosopher extends Thread
{ 
	/**
	 * Philosopher 类的构造函数。
	 * 
	 * @param HOST DiningPhils 类型的参数,
	 * @param i 哲学家标号。
	 */
 public Philosopher( DiningPhils HOST , int i )
 {
	 host = HOST;
	 philo_num = i;
 }
 
 /**
  * 吃饭方法。<p>
  * 线程暂停一段时间,然后设置吃饭状态为false,放下筷子。
  */
 private void eat()
 {
	 pause();
	 setEat( false );
	 putDownChops();
 }
 
 /**
  * 思考的方法。<p>
  * 调用暂停函数,线程暂停一段时间。
  */
 private void think()
 {
	 pause ( );
 }
 
 /**
  * 覆盖了Thread类中run()函数,启动线程运行的方法。<p>
  * 按顺序分别执行拿起筷子,吃饭,思考的方法。
  */
 public void run()
 {
	 while(true)
    {
		 grabChopsticks();
		 eat();
		 think();
    }
 }
 
 /**
  * 设置时间间隔的方法。
  * 
  * @param TS 随即产生的时间参数。
  */
 public void setTimeSlice( int TS )
 {
	 ts = TS;
 }
 
 /**
  * 判断哲学家左右筷子是否都可用的方法。<p>
  * 只有左右两边的筷子都可用时才可以拿起两边的筷子,这样可以防止死锁的发生。
  * 
  * @return boolean 类型的值。
  *         ture 表示哲学家左右两边的筷子都可用,false表示至少有一个不可用。
  */
 public boolean chopsticksFree()
 {
	 return !host.getChopstick( philo_num ) && 
	 	!host.getChopstick ( ( philo_num + 1 ) % host.getCount ( ) );
 }
 
 /**
  * 设置哲学家左边筷子状态的方法。
  * 
  * @param flag 传入的boolean类型的状态参数,ture表示被拿起,false表示未使用。
  */
 public void setLeftChopstick( boolean flag )
 {
	 host.setChopstick ( philo_num , flag );   
	 //调用正在进餐的哲学家类,设置当前正在进餐的哲学家的右筷子状态
 }
 
 /**
  * 设置哲学家右边筷子状态的方法。
  * 
  * @param flag 传入的boolean类型的状态参数
  */
 public void setRightChopstick( boolean flag )
 {
	 host.setChopstick ( ( philo_num + 1 ) % host.getCount ( ) , flag );
	 //调用正在进餐的哲学家类,设置当前正在进餐的哲学家的左筷子状态
 }
 
 /**
  * 放下筷子的方法,将左右筷子的状态都设置为放下状态。
  */
 private void putDownChops()
 {
	 setLeftChopstick ( false );   //设为放下状态
	 setRightChopstick ( false );
 }
 
 /**
  * 临界区函数,确保哲学家在没有筷子或筷子不够时思考,满足条件后才就餐。<br>
  * 此方法是关键代码,不允许两个线程同时访问该部分。
  */
 private synchronized void grabChopsticks() 
 {
	 while( !chopsticksFree ( ) )  //判断左右两边的筷子是否都可用,若其中有一个
		 					       //筷子不可用则将那块泽的操作挂起,直到两边都可用为止
	 {
		 try
		 {
			 wait();    
		 }
		 catch( InterruptedException e){}
	 }
	 takeChopsticks();            //拿起两边的筷子
	 notifyAll();				  //唤醒所有调用该对象wait()的哲学家,等待时间最长
	 							  //的哲学家得到该线程对象的锁
 }
 
 /**
  * 拿筷子的方法。<p>
  * 将左右筷子设为不可用,并设定吃饭状态,显示此时的哲学家和筷子的状态。
  */
 private void takeChopsticks()
 {
	 setLeftChopstick( true );
	 setRightChopstick( true );
	 setEat(true);
	 host.dumpStatus();       //显示状态
 }
 
 /**
  * 线程暂停方法。<br>
  */
 private void pause ()
 {
	 setTimeSlice ( host.generateTimeSlice ( ) );  
	 try
	 {
		 sleep ( ts*1000 );
	 }
	 catch ( InterruptedException e ){ }
 }
 
 /**
  * 设置吃饭的状态。
  * 
  * @param v boolean 类型的参数,ture为正在吃饭,反之为false.
  */
 private void setEat ( boolean v )
 {
	 isEating = v;
 }
 
 /**
  * 得到吃饭状态。
  * 
  * @return isEating boolean类型的参数,ture为正在吃饭,反之为false.
  */
 public boolean getEat()
 {
	 return isEating;
 }

 private DiningPhils host;
 private boolean isEating;
 private int philo_num; 
 private int ts;
}
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -