哲学家就餐问题(java实现)

news/2024/5/20 14:20:01 标签: 哲学家就餐问题, 多线程, 死锁, java

1 问题概述
哲学家就餐问题,是并行程序中的一个经典问题,其描述如下。
1. 圆桌上有五位哲学家,每两人中间有一个筷子。
2. 每个哲学家有两件事情要做:
    (1) 思考;
    (2) 吃饭。哲学家必须同时拿到两只筷子,才能吃饭。
3. 哲学家之间并不知道对方何时要吃饭,何时要思考,不能协商制定分时策略。
4. 设计一个拿筷子的策略,使得哲学家之间不会因为拿筷子而出现死锁或者活锁。

2代码实现

  • 版本一(没有很好的解决死锁问题)

       当五个哲学家同时拿起左筷子,进入死锁状态

java">package com.cch;

public class Philosopher extends Thread{
	private static int[] chopsticks = {1,1,1,1,1};
	private int id;
	
	public Philosopher(int id){
		this.id = id;
	}
	
	@Override
	public synchronized void run() {
		this.eat();
		this.think();
	}
	
	public void think(){
		//左筷子放下
		this.chopsticks[this.id] = 1;
		//右筷子放下
		this.chopsticks[(this.id+1)%this.chopsticks.length] = 1;
		System.out.println("哲学家_" + this.id + "正在思考");
		
		//思考一秒时间
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void eat(){
		//拿起左筷子
		while(true){
			if(this.chopsticks[this.id] != 0){
				chopsticks[this.id] = 0;
				System.out.println("哲学家_" + this.id + "拿起了左筷子");
				break;
			}else{
				try {
					this.wait(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					System.out.println("哲学家_" + this.id + "的左筷子正在被哲学家_"+((this.id-1+this.chopsticks.length)%this.chopsticks.length)+"使用,等待1000ms");
				}
			}
		}
		
		
		//拿起右筷子
		while(true){
			if(this.chopsticks[(this.id+1)%this.chopsticks.length] != 0){
				chopsticks[(this.id+1)%this.chopsticks.length] = 0;
				System.out.println("哲学家_" + this.id + "拿起了右筷子");
				break;
			}else{
				try {
					this.wait(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					System.out.println("哲学家_" + this.id + "的右筷子正在被哲学家_"+((this.id+1)%this.chopsticks.length)+"使用,等待1000ms");
				}
			}
		}
		System.out.println("哲学家_" + this.id + "正在吃饭");
		
		//吃饭花一秒时间
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.notify();
	}
	
	public static void main(String[] args) {
		new Philosopher(0).start();
		new Philosopher(1).start();
		new Philosopher(2).start();
		new Philosopher(3).start();
		new Philosopher(4).start();
	}
}

  • 版本二(超时释放法)

    当五个哲学家同时拿起左筷子时,线程进入死锁,等待2s后,就会有哲学家会放下右筷子,死锁解除

java">package com;

public class Philosopher extends Thread{
	private static int[] chopsticks = {1,1,1,1,1};
	private int id;
	
	public Philosopher(int id){
		this.id = id;
	}
	
	@Override
	public synchronized void run() {
		this.eat();
		this.think();
	}
	
	public void think(){
		//左筷子放下
		this.chopsticks[this.id] = 1;
		//右筷子放下
		this.chopsticks[(this.id+1)%this.chopsticks.length] = 1;
		System.out.println("哲学家_" + this.id + "正在思考");
		
		//思考一秒时间
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void eat(){
		//拿起左筷子
		while(true){
			if(this.chopsticks[this.id] != 0){
				chopsticks[this.id] = 0;
				System.out.println("哲学家_" + this.id + "拿起了左筷子");
				break;
			}else{
				try {
					this.wait(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					System.out.println("哲学家_" + this.id + "的左筷子正在被哲学家_"+((this.id-1+this.chopsticks.length)%this.chopsticks.length)+"使用,等待1000ms");
				}
			}
		}
		
		
		//拿起右筷子
		while(true){
			if(this.chopsticks[(this.id+1)%this.chopsticks.length] != 0){
				chopsticks[(this.id+1)%this.chopsticks.length] = 0;
				System.out.println("哲学家_" + this.id + "拿起了右筷子");
				break;
			}else{
				try {
					this.wait(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally{
					System.out.println("哲学家_" + this.id + "的右筷子正在被哲学家_"+((this.id+1)%this.chopsticks.length)+"使用,等待1000ms");
				}
			}
		}
		System.out.println("哲学家_" + this.id + "正在吃饭");
		
		//吃饭花一秒时间
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.notify();
	}
	
	public static void main(String[] args) {
		new Philosopher(0).start();
		new Philosopher(1).start();
		new Philosopher(2).start();
		new Philosopher(3).start();
		new Philosopher(4).start();
	}
}

  • 版本三(服务生解法)

    添加一个服务生,只有当经过服务生同意之后才能拿筷子,服务生负责避免死锁发生。

java">package com.cch.Philosopher;

class Philosopher extends Thread{
    private String name;
    private Fork fork;
    public Philosopher(String name,Fork fork){
        super(name);
        this.name=name;
        this.fork=fork;
    }
    
    public void run(){
        while(true){
            thinking();
            fork.takeFork();
            eating();
            fork.putFork();
        }
        
    }
    
    
    public void eating(){
        System.out.println("I am Eating:"+name);
        try {
            sleep(1000);//吃饭花一秒
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
    public void thinking(){
        System.out.println("I am Thinking:"+name);
        try {
            sleep(1000);//思考花一秒
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class Fork{
    private boolean[] used={false,false,false,false,false,false};
    
    /*只有当左右手的筷子都未被使用时,才允许获取筷子,且必须同时获取左右手筷子*/
    public synchronized void takeFork(){
        String name = Thread.currentThread().getName();
        int i = Integer.parseInt(name);
        while(used[i]||used[(i+1)%5]){
            try {
                wait();//如果左右手有一只正被使用,等待
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        used[i ]= true;
        used[(i+1)%5]=true;
    }
    
    /*必须同时释放左右手的筷子*/
    public synchronized void putFork(){
        String name = Thread.currentThread().getName();
        int i = Integer.parseInt(name);
        
        used[i ]= false;
        used[(i+1)%5]=false;
        notifyAll();//唤醒其他线程
    }
}

public class ThreadTest {

    public static void main(String []args){
        Fork fork = new Fork();
        new Philosopher("0",fork).start();
        new Philosopher("1",fork).start();
        new Philosopher("2",fork).start();
        new Philosopher("3",fork).start();
        new Philosopher("4",fork).start();
    }
}
  • 版本四(资源分级法)

    请自行百度

  • 版本五(Chandy/Misra解法)

    请自行百度




http://www.niftyadmin.cn/n/770082.html

相关文章

有效的数独

LeetCode 之 有效的数独 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 上图是一个部分填充的有…

Lua协程实现原理

相关 API API 传入参数 返回值 说明 API传入参数返回值说明create(f)函数,作为协程运行的主函数返回创建的协程如果还需要运行,需要使用resume操作resume(co,[val1,…])传入第一个参数是create函数返回的协程,剩下的参数是传递给协程运行的…

百度网盘搜索引擎

百度网盘搜索: 1 .网盘屋:http://www.wangpanwu.com 这里已经有很多热门资源,分享达人,排行什么的。很容易利用达人分享空间收集资源。 2.度盘搜:http://www.dupansou.com/ 这还有一个主站和华为站。不过主站貌似搜不到…

windows系统下mysql修改默认字符编码

问题:由于安装MySQL时没有修改默认的字符编码(liatin1),运行时发现保存不了中文 修改MySQL字符编码方法如下: 关闭MySQL服务 dos命令关闭:net stop mysql 手动关闭:如图修改MySQL的安装目录下的my.ini(My…

关于Unity中渲染的优化

前言 最近在看shader入门精要一书,里面大概指出了GPU的优化,入门精要嘛。 翻阅官方文档,和参考一些博文,比较杂,因此,很有必要整理,这篇文章主要是针对渲染相关的,和CS脚本&#xf…

Hibernate4.3.11 如何去掉红色的日志文字

​ 四月13, 2017 2:41:11 下午 org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final} 四月 13, 2017 2:41:11 下午 org.hibernate.Version logVersion INFO: HHH000412: H…

二叉树的遍历C#实现,递归以及非递归

前序遍历 输出规则 根节点&#xff0c; 左子树&#xff0c; 右子树。 二叉树的前序遍历规则是从根节点开始&#xff0c;依层 逐层取 左子节点&#xff0c;若此节点没有 左子节点&#xff0c;说明此节点是叶子节点&#xff0c;往上 回溯&#xff0c; 取 最小父节点的右节点&am…

UnityUGUI源码阅读之Graphic

关于Graphic组件 Graphic组件是UGUI中比较重要的一个组件&#xff0c;例如Image,RawImag,MaskableGraphic 可遮罩的图形组件 这些都是继承自Graphic的 它必须要有 CanvasrRenderer组件以级RectTransform 组件&#xff0c;并且一个对象只允许挂载一个。 RectTransform: RectTra…