java 多线程实现 哲学家进餐问题


/**
 * 在1965年,Dijkstra提出并解决了一个他称之为哲学家进餐的同步问题。从那时起,每个发明新的同步原语的人都希望通过解决哲学家进餐间题来展示其同步原语的精妙之处。这个问题可以简单地描述:五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一碟通心面,由于面条很滑,所以要两把叉子才能夹住。相邻两个碟子之间有一把叉子。
 *   哲学家的生活包括两种活动:即吃饭和思考。当一个哲学家觉得饿时,他就试图去取他左边和右边的叉子。如果成功地获得两把叉子,他就开始吃饭,吃完以后放下叉子继续思考。
 *   要保证哲学家不能饿死,就是就餐数一直为0;不能出现死锁和活锁.
 * @author lijianji
 *
 */
public class Test2 {

	public static void main(String[] args) {
		Fork aFork=new Fork("a");
		Fork bFork=new Fork("b");
		Fork cFork=new Fork("c");
		Fork dFork=new Fork("d");
		Fork eFork=new Fork("e");
		
		Scientist scientistA=new Scientist("A",eFork,aFork);
		Scientist scientistB=new Scientist("B",aFork,bFork);
		Scientist scientistC=new Scientist("C",bFork,cFork);
		Scientist scientistD=new Scientist("D",cFork,dFork);
		Scientist scientistE=new Scientist("E",dFork,eFork);
		
		new Thread(scientistA).start();
		new Thread(scientistC).start();
		new Thread(scientistB).start();
		new Thread(scientistE).start();
		new Thread(scientistD).start();
	}
}

/**
 * 科学家
 * @author lijianji
 *
 */
class Scientist implements Runnable{

	private String name;
	
	/**
	 * 左餐叉
	 */
	private Fork  leftFork;
	
	/**
	 * 右餐叉
	 */
	private Fork  rightFork;
	
	/**
	 * 就餐次数
	 */
	private int counts=0;
	
	public Scientist(String name,Fork leftFork, Fork rightFork){
		this.name=name;
		this.leftFork=leftFork;
		this.rightFork=rightFork;
	}
	
	@Override
	public void run() {
		//随机开始就餐或思考
			int k=(int)Math.random()*10;
			if(k%2==0){
				this.dining();
			}else{
				this.thinking();
			}
		
		
	}
	
	/**
	 * 进餐
	 */
	private void dining(){
		try {
				synchronized (leftFork) {
					synchronized (rightFork) {
						counts++;
						System.out.println(name + ",开始进餐" + ", 用餐次数:" + counts
								+ ", leftFork:" + leftFork.getName()
								+ ", rightFork:" + rightFork.getName());
						for (int i = 0; i < 10; i++) {
							//	System.out.println("\t\t\t\t "+name+":用餐时间:"+i);
							Thread.sleep(100);
						}
					}
				}
			this.thinking();
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
	}
	
	/**
	 * 思考
	 */
	private void thinking(){
		
		try {
			Thread.sleep(2000);
//			System.out.println(name+":思考 完2s,开始抢餐叉");
			this.dining();
			
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
	}
	
}

/**
 * 餐叉
 * @author lijianji
 *
 */
class Fork{
	private String name;
	
	
	public Fork(String name){
		this.name=name;
	}
	
	
	public String getName(){
		return name;
	}
}


  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
哲学家进餐问题是一个经典的同步问题,主要涉及到多个进程(哲学家)之间的资源竞争问题。在这个问题中,每个哲学家都需要交替地进行思考和进餐,但是他们共享一些资源,如餐具等,因此需要协调它们的行为以避免死锁和饥饿等问题。 下面是使用 Java 实现哲学家进餐问题的示例代码: ```java import java.util.concurrent.Semaphore; public class Philosopher implements Runnable { private final int id; private final Semaphore leftFork; private final Semaphore rightFork; public Philosopher(int id, Semaphore leftFork, Semaphore rightFork) { this.id = id; this.leftFork = leftFork; this.rightFork = rightFork; } @Override public void run() { try { while (true) { think(); leftFork.acquire(); rightFork.acquire(); eat(); rightFork.release(); leftFork.release(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } private void think() throws InterruptedException { System.out.println("Philosopher " + id + " is thinking"); Thread.sleep((long) (Math.random() * 5000)); } private void eat() throws InterruptedException { System.out.println("Philosopher " + id + " is eating"); Thread.sleep((long) (Math.random() * 5000)); } } public class DiningPhilosophers { private static final int NUM_PHILOSOPHERS = 5; public static void main(String[] args) { Semaphore[] forks = new Semaphore[NUM_PHILOSOPHERS]; for (int i = 0; i < NUM_PHILOSOPHERS; i++) { forks[i] = new Semaphore(1); } Philosopher[] philosophers = new Philosopher[NUM_PHILOSOPHERS]; for (int i = 0; i < NUM_PHILOSOPHERS; i++) { philosophers[i] = new Philosopher(i, forks[i], forks[(i + 1) % NUM_PHILOSOPHERS]); new Thread(philosophers[i]).start(); } } } ``` 在这个示例代码中,我们创建了一个 `Philosopher` 类和一个 `DiningPhilosophers` 类,其中 `Philosopher` 类实现了哲学家的行为,而 `DiningPhilosophers` 类则负责创建和启动哲学家线程。 在 `Philosopher` 类中,我们使用了两个信号量 `leftFork` 和 `rightFork` 表示哲学家左边和右边的餐叉。在 `run` 方法中,哲学家先思考一段时间,然后尝试获取左右餐叉的信号量。如果成功获取了两个餐叉的信号量,哲学家就可以进餐。最后,哲学家释放左右餐叉的信号量,以便其他哲学家可以使用它们。 在 `DiningPhilosophers` 类中,我们首先创建了一个 `Semaphore` 数组 `forks`,其中每个元素都表示一个餐叉。然后,我们创建了五个 `Philosopher` 对象,并将它们的左右餐叉设置为相邻的两个 `Semaphore` 对象。最后,我们创建了五个线程,每个线程都对应一个哲学家,并启动它们。当程序运行时,每个哲学家会交替进行思考和进餐,直到程序被中断或终止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值