【ThinkingInJava】63、哲学家进餐问题

/**
* 书本:《Thinking In Java》
* 功能:哲学家进餐问题
* 		作为哲学家,他们很穷,所以他们只能买五根筷子。他们围坐在桌子周围,每人之间放一根筷子。当一个哲学家要就餐的时候了,这个哲学家必须同时得到左边
* 		和右边的筷子。如果一个哲学家左边或右边的筷子已经有人在使用筷子了,那么这个哲学家就必须等待,直至可以得到必须的筷子
* 文件:Chopstick.java
* 时间:2015年5月9日15:08:21
* 作者:cutter_point
*/
package Lesson21Concurency;

public class Chopstick
{
	private boolean taken = false;		//筷子是否已经被拿起来了
	public synchronized void take() throws InterruptedException
	{
		while(taken)
			this.wait();  //如果筷子被拿起来了,那么就得等待,等待其他进程对他进行唤醒
		taken = true; 	//如果没有拿起来,那么调用这个函数筷子被取起来了
	}

	public synchronized void drop()	//这个函数是放下筷子
	{
		taken = false;
		this.notifyAll(); //唤醒别人,这个筷子又可以使用了
	}
}
/**
* 书本:《Thinking In Java》
* 功能:哲学家进餐问题
* 		作为哲学家,他们很穷,所以他们只能买五根筷子。他们围坐在桌子周围,每人之间放一根筷子。当一个哲学家要就餐的时候了,这个哲学家必须同时得到左边
* 		和右边的筷子。如果一个哲学家左边或右边的筷子已经有人在使用筷子了,那么这个哲学家就必须等待,直至可以得到必须的筷子
* 文件:Philosopher.java
* 时间:2015年5月9日15:17:36
* 作者:cutter_point
*/
package Lesson21Concurency;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import static net.mindview.util.Print.*;

public class Philosopher implements Runnable	//一个哲学家线程
{
	//哲学家左右两边有两双筷子,这名哲学家得id号,给一个数据,用来判断哲学家是思考还是进餐
	private Chopstick left;		//左筷子
	private Chopstick right;	//右筷子
	private final int id;		//这名哲学家得id号
	private final int ponderFactor; 		//一个数据用来判定是否会思考还是进餐
	private Random rand = new Random(998);

	public Philosopher(Chopstick left, Chopstick right, int ident, int ponder)
	{
		this.left = left;
		this.right = right;
		this.id = ident;		//哲学家的id号码
		this.ponderFactor = ponder; 		//哲学家思考数据
	}

	private void pause() throws InterruptedException
	{
		if(this.ponderFactor == 0)
		{
			//如果哲学家得思考数据是0的话,那么就不用暂停思考了,直接返回
			return;
		}
		//如果哲学家要思考的话,那么我们就要让他暂停一段时间
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(this.ponderFactor * 1500)); 	//思考时间
	}

	public String toString()
	{
		return "哲学家:" + this.id + " 号 ";
	}

	@Override
	public void run()
	{
		//哲学家的行动模式
		//收先,如果哲学家还在餐桌上,也就是没有被中断
		try
		{
			while(!Thread.interrupted())
			{
				//1、首先哲学家会思考
				print(this + " " + " 在思考");
				this.pause(); 	//思考一段时间
				//2、思考一段时间后觉得饿了,那么哲学家就要进餐了,那么就会拿起来左边和右边的筷子,然后开始进餐,进餐额时间又会有一段
				this.right.take(); 	//拿起筷子
				print(this + " " + "拿起右边的筷子");
				this.left.take();
				print(this + " " + "拿起左边的筷子");
				print(this + " " + "开始吃饭");
				this.pause(); //吃饭花的时间
				//3、吃完之后就会放下左右的筷子
				print(this + " " + "吃完了,放下筷子");
				this.left.drop();
				this.right.drop();
			}
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
			print(this + " " + " 被中断了退出了餐桌。");
		}
	}

}
/**
* 书本:《Thinking In Java》
* 功能:哲学家进餐问题
* 		作为哲学家,他们很穷,所以他们只能买五根筷子。他们围坐在桌子周围,每人之间放一根筷子。当一个哲学家要就餐的时候了,这个哲学家必须同时得到左边
* 		和右边的筷子。如果一个哲学家左边或右边的筷子已经有人在使用筷子了,那么这个哲学家就必须等待,直至可以得到必须的筷子
* 文件:DeadlockingDiningPhilosophers.java
* 时间:2015年5月9日15:36:13
* 作者:cutter_point
*/
package Lesson21Concurency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DeadlockingDiningPhilosophers
{

	public static void main(String[] args) throws Exception
	{
		int ponder = 5;
		int size = 5;		//哲学家得
		ExecutorService exec = Executors.newCachedThreadPool(); 		//线程连接池
		Chopstick[] sticks = new Chopstick[size];	//创建数组空间
		for(int i = 0; i < size; ++i)
			sticks[i] = new Chopstick();	//初始化数组里面的对象
		for(int i = 0; i < size; ++i)
		{
			exec.execute(new Philosopher(sticks[i], sticks[(i+1) % size], i, ponder));
		}

		if(args.length == 3 && args[2].equals("timeout"))
			TimeUnit.SECONDS.sleep(5);
		else
		{
			System.out.println("回车键退出");
			System.in.read();
		}
		exec.shutdownNow();		//停止全部线程
	}

}

输出:

回车键退出

哲学家:4 号   在思考  obj1

哲学家:1 号   在思考  obj1

哲学家:3 号   在思考  obj1

哲学家:2 号   在思考  obj1

哲学家:0 号   在思考  obj1

哲学家:3 号  拿起右边的筷子  obj1

哲学家:2 号  拿起右边的筷子  obj1

哲学家:1 号  拿起右边的筷子  obj1

哲学家:0 号  拿起右边的筷子  obj1

哲学家:4 号  拿起右边的筷子  obj1

java.lang.InterruptedException

哲学家:3 号   被中断了退出了餐桌。  obj1

哲学家:0 号   被中断了退出了餐桌。  obj1

哲学家:1 号   被中断了退出了餐桌。  obj1

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

哲学家:2 号   被中断了退出了餐桌。  obj1

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

哲学家:4 号   被中断了退出了餐桌。  obj1

这个会导致死锁,也就是共享的有限资源不够,被多个线程争抢的时候的情况

改进:

/**
* 书本:《Thinking In Java》
* 功能:哲学家进餐问题
* 		作为哲学家,他们很穷,所以他们只能买五根筷子。他们围坐在桌子周围,每人之间放一根筷子。当一个哲学家要就餐的时候了,这个哲学家必须同时得到左边
* 		和右边的筷子。如果一个哲学家左边或右边的筷子已经有人在使用筷子了,那么这个哲学家就必须等待,直至可以得到必须的筷子
* 文件:FixedDiningPhilosophers.java
* 时间:2015年5月9日15:36:13
* 作者:cutter_point
*/
package Lesson21Concurency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class FixedDiningPhilosophers
{

	public static void main(String[] args) throws Exception
	{
		int ponder = 5;
		int size = 5;		//哲学家得
		ExecutorService exec = Executors.newCachedThreadPool(); 		//线程连接池
		Chopstick[] sticks = new Chopstick[size];		//创建数组空间
		for(int i = 0; i < size; ++i)
			sticks[i] = new Chopstick();	//初始化数组里面的对象
		for(int i = 0; i < size; ++i)
		{
//			exec.execute(new Philosopher(sticks[i], sticks[(i+1) % size], i, ponder));
			if(i < (size - 1))
				exec.execute(new Philosopher(sticks[0], sticks[i+1], i, ponder));
			else
				exec.execute(new Philosopher(sticks[0], sticks[i], i, ponder));
		}

		if(args.length == 3 && args[2].equals("timeout"))
			TimeUnit.SECONDS.sleep(5);
		else
		{
			System.out.println("回车键退出");
			System.in.read();
		}
		exec.shutdownNow();		//停止全部线程
	}

}

输出:

回车键退出

哲学家:2 号   在思考  obj1

哲学家:0 号   在思考  obj1

哲学家:4 号   在思考  obj1

哲学家:1 号   在思考  obj1

哲学家:3 号   在思考  obj1

哲学家:2 号  拿起右边的筷子  obj1

哲学家:2 号  拿起左边的筷子  obj1

哲学家:2 号  开始吃饭  obj1

哲学家:4 号  拿起右边的筷子  obj1

哲学家:1 号  拿起右边的筷子  obj1

哲学家:0 号  拿起右边的筷子  obj1

哲学家:2 号  吃完了,放下筷子  obj1

哲学家:2 号   在思考  obj1

哲学家:0 号  拿起左边的筷子  obj1

哲学家:0 号  开始吃饭  obj1

哲学家:0 号  吃完了,放下筷子  obj1

哲学家:0 号   在思考  obj1

哲学家:4 号  拿起左边的筷子  obj1

哲学家:4 号  开始吃饭  obj1

哲学家:4 号  吃完了,放下筷子  obj1

哲学家:4 号   在思考  obj1

哲学家:1 号  拿起左边的筷子  obj1

哲学家:3 号  拿起右边的筷子  obj1

哲学家:1 号  开始吃饭  obj1

哲学家:1 号  吃完了,放下筷子  obj1

哲学家:1 号   在思考  obj1

哲学家:3 号  拿起左边的筷子  obj1

哲学家:3 号  开始吃饭  obj1

哲学家:3 号  吃完了,放下筷子  obj1

哲学家:3 号   在思考  obj1

哲学家:2 号  拿起右边的筷子  obj1

哲学家:2 号  拿起左边的筷子  obj1

哲学家:2 号  开始吃饭  obj1

哲学家:0 号  拿起右边的筷子  obj1

哲学家:4 号  拿起右边的筷子  obj1

哲学家:1 号  拿起右边的筷子  obj1

哲学家:2 号  吃完了,放下筷子  obj1

哲学家:2 号   在思考  obj1

哲学家:1 号  拿起左边的筷子  obj1

哲学家:1 号  开始吃饭  obj1

哲学家:2 号  拿起右边的筷子  obj1

哲学家:1 号  吃完了,放下筷子  obj1

哲学家:1 号   在思考  obj1

哲学家:2 号  拿起左边的筷子  obj1

哲学家:2 号  开始吃饭  obj1

哲学家:1 号  拿起右边的筷子  obj1

哲学家:2 号  吃完了,放下筷子  obj1

哲学家:2 号   在思考  obj1

哲学家:1 号  拿起左边的筷子  obj1

哲学家:1 号  开始吃饭  obj1

哲学家:2 号  拿起右边的筷子  obj1

哲学家:1 号  吃完了,放下筷子  obj1

哲学家:1 号   在思考  obj1

哲学家:2 号  拿起左边的筷子  obj1

哲学家:2 号  开始吃饭  obj1

哲学家:1 号  拿起右边的筷子  obj1

java.lang.InterruptedException

哲学家:3 号   被中断了退出了餐桌。  obj1

哲学家:0 号   被中断了退出了餐桌。  obj1

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:63)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException: sleep interrupted

at java.lang.Thread.sleep(Native Method)

at java.lang.Thread.sleep(Thread.java:340)

at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)

at Lesson21Concurency.Philosopher.pause(Philosopher.java:42)

at Lesson21Concurency.Philosopher.run(Philosopher.java:68)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

哲学家:2 号   被中断了退出了餐桌。  obj1

java.lang.InterruptedException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

java.lang.InterruptedException哲学家:4 号   被中断了退出了餐桌。  obj1

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:503)

at Lesson21Concurency.Chopstick.take(Chopstick.java:18)

at Lesson21Concurency.Philosopher.run(Philosopher.java:65)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

at java.lang.Thread.run(Thread.java:744)

哲学家:1 号   被中断了退出了餐桌。  obj1

这个不会死锁,只要当你回车的时候才会结束各个线程之间的配合

时间: 2024-11-05 12:18:13

【ThinkingInJava】63、哲学家进餐问题的相关文章

利用Linux下的pthread_mutex_t类型来实现哲学家进餐问题

首先说一下什么是哲学家进餐问题,这是操作系统课程中一个经典的同步问题, 问题如下:如上图,有6个哲学家和6根筷子(那个蓝色部分表示哲学家,那个紫色长条部分表示筷子),他们分别被编了0~5的号!如果某个哲学家想要进餐的话,必须同时拿起左手和右手边的两根筷子才能进餐!哲学家进餐完毕之后,就放下手中拿起的两根筷子!这样其他哲学家就能拿这些筷子进餐了!注意这个哲学家的个数必须是偶数个! OK,这样就可能存在一个死锁问题,比如0号哲学家拿了0号筷子,1号哲学家拿了1号筷子!如此往复,最终的结果就是每个哲学

哲学家进餐问题

先直接上代码 1 #define N 5 /* 哲学家数目 */ 2 #define LEFT (i+N-1)%N /* i的左邻编号 */ 3 #define RIGHT (i+ 1)%N /* i的右邻编号 */ 4 #define THINKING 0 /* 哲学家在思考 */ 5 #define HUNGRY 1 /*哲学家试图拿起叉子 */ 6 #define EATING 2 /* 哲学家进餐 */ 7 typedef int semaphore; /*信号量 */ 8 int st

【操作系统】经典的同步问题(生产者消费者问题, 哲学家进餐问题, 读写问题)

用专业术语来说, 进程是程序的一次动态执行.说简单点, 就是进程是系统中的某个任务.操作系统中有多个任务需要执行, 那么怎样执行才能使它们同步呢? 即如何让任务并发执行互不影响呢? 这就引出了进程同步中的经典问题: 生产者消费者问题, 哲学家进餐问题, 读写问题 生产者-消费者问题 有一群生产者进程在生产产品, 并将这些产品提供给消费者进程取消费. 为使生产者进程与消费者进程能并发进行, 在两者间设置了一个具有n个缓冲区的缓冲池, 生产者进程将其所生产的产品翻入缓冲区中, 消费者进程可从一个缓冲

哲学家进餐

问题描述 一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭,如图2-10所示.哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人.只有当哲学家饥饿的时候,才试图拿起左. 右两根筷子(一根一根地拿起).如果筷子已在他人手上,则需等待.饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考. 问题分析 1) 关系分析.5名哲学家与左右邻居对其中间筷子的访问是互斥关系. 2) 整理思路.显然这里有五个进程.本题的关键是如何让一个哲

java笔记--超级类Object多线程的应用+哲学家进餐算法内部类与多线程结合

关于Object类中的线程方法: Object类是所有Java类的 父类,在该类中定义了三个与线程操作有关的方法,使得所有的Java类在创建之后就支持多线程 这三个方法是:notify(),notifyAll(),wait(),这几个方法都是用来控制线程的运行状态的. 方法列表如下: notify() : 唤醒在此对象监视器上等待的单个线程 notifyAll() : 唤醒在此对象监视器上等待的所有线程 wait() : 在其他线程时调用此对象的notify()或者notifyAll()方法前,

【操作系统总结】哲学家进餐问题

哲学家进餐问题 问题:有五个哲学家公用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,平时一个哲学家进行思考,饿的时候便取用左右做靠近他的筷子,只有他拿到两只筷子时才能进餐,进餐完毕继续思考 利用记录型信号量解决问题 semaphore chopstick[5] = {1, 1, 1, 1, 1};//每一个筷子一个信号量 do { wait(chopstick[i]);//首先这个筷子能不能拿到,否则自我阻塞 wait(chopstick[(i + 1) % 5]);//再判断

Java总结(十)—实现Runnable接口创建线程,线程安全同步,死锁(哲学家进餐问题),读写锁

一.通过实现Runnable接口创建线程 定义实现Runnable接口的类 (1)Runnable接口中只有一个方法public void run();用来定义线程运行体: class MyRun implements Runnable(){ public void run(){ 线程执行的具体代码 } } (2)创建线程的实例的时候将这个类的实例作为参数传递到线程实例内部.然后再启动: Thread thread=new Thread(new MyRun()); Thread.start();

经典进程的同步问题之——哲学家进餐

哲学家进餐问题描述 由Dijkstra提出并解决哲学家进餐问题(The Dinning Philosophers Problem)是经典的同步问题.该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有五个碗和五只筷子,他们的生活方式是交替的进行思考和进餐.平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有他拿到两只筷子时才能进餐,进餐完毕继续进行思考. 1 利用记录型信号量解决哲学家进餐问题 经过分析可知,圆桌上的筷子是临界资源,在一段时间内只允许一位哲学

信号量解决哲学家进餐问题

参考线程同步之信号量(sem_init,sem_post,sem_wait) - 郑志强Aloha - 博客园 以及<操作系统概念>第七版 第六章 项目:生产者-消费者问题 题目描述: 哲学家进餐问题描述有五个哲学家,他们的生活方式是交替地进行思考和进餐,n哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,n平时哲学家进行思考,饥饿时便试图取其左.右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,n进餐完毕,放下筷子又继续思考. 如图. 编号都为0-4.哲学家0-3左