码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-05-23 10:07:37      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:java编程思想   哲学家进餐   线程   死锁   

/**
* 书本:《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

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






































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

标签:java编程思想   哲学家进餐   线程   死锁   

原文地址:http://blog.csdn.net/cutter_point/article/details/45932165

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!