记得大二时学操作系统,有个关于锁的经典模型——哲学家模型。当时老师要求我们用程序实现,我当时没做出来,一直耿耿于怀。今天看Java cookbook中的线程介绍。于是动手来试下,花了一天才弄出来。在此把大概过程罗列如下,也算是交几年前的作业吧。

程序的设计分两部分:哲学家问题的逻辑处理、图形化展示结果部分。最终效果如下:

图1:初始时五个哲学家都在睡眠

图2::哲学家0、3在睡眠,1、4在吃饭,2挨饿

图3:哲学家0、3在吃饭,1在挨饿,2、4在睡眠

首先做一点约定:

对于哲学家按顺时针计算,最顶部的哲学家为0,右边的为1,右下角为2……。

对于筷子见图1,哲学家0、1夹着的筷子为0,按顺时针递增,即1、2中间的筷子为1……

至于什么是哲学家问题,若忘记了可以翻阅下操作系统温习下,简单的描述下:有五个哲学家要吃饭,同时只有五个筷子,为了吃饭必须同时获得两个筷子。如果每个哲学家都是先拿左边筷子再拿右边筷子,则必然发生死锁。所以规定了奇数的先拿左边,偶数的先拿右边。由此可见,筷子是竞争资源。准确的讲,

筷子0是哲学家0、1竞争的资源;

筷子1是哲学家1、2竞争的资源;

筷子2是哲学家2、3竞争的资源;

筷子3是哲学家3、4竞争的资源;

筷子4是哲学家4、0竞争的资源;

类图如下:

所有的逻辑都在Person中完成。Person是一个继承了Thread的线程。在PhilosopherDining的main方法中实例化了五个Person并start了他们。现在我们看下Person的run方法及其涉及的其他方法:

/**
* 不断的睡眠、吃饭.
*
* @see java.lang.Thread#run()
*/public void run() {while (!done) {sleeping();eat();}
}/**
* 睡眠几秒钟.
*/public void sleeping() {try {// id睡觉guiMgr.setPersonSleeping(id);System.out.println("Person[" + id + "] is sleeping...");Thread.sleep(SLEEP_TIME);} catch (InterruptedException e) {e.printStackTrace();}
}/**
* 吃饭,必须同时得到左右筷子才能吃.
*/public void eat() {// 奇数的先拿左边if (isOdd(id)) {// 先拿左边getChopstick(leftNo);// 再拿右边getChopstick(rightNo);} else {// 偶数的先拿右边// 先拿右边getChopstick(rightNo);// 再拿左边getChopstick(leftNo);}// 两边都拿到的话则可以放心的吃东西了eating();}

很简单,先睡眠几分钟,饿醒了就吃东西。吃东西又需要先拿左/右边的筷子再拿右/左边的筷子,然后才能吃。关键就在拿筷子getChopstick、吃饭eating这两件事上。

/**
* 试图获取筷子,若被他人先拿则需等待.
*
* @param chopstickNo
*            要拿的筷子号
*/private void getChopstick(final int chopstickNo) {System.out.println("id:" + id + " no:" + chopstickNo);synchronized (chopsticks[chopstickNo]) {while (chopsticks[chopstickNo].isUsed()) {System.out.println("Person[" + id + "] is waiting  Chopstick[" + chopstickNo + "]");try {// 吃不到东西,哭了guiMgr.setPersonCrying(id);chopsticks[chopstickNo].wait();} catch (InterruptedException e) {e.printStackTrace();}}}// 获取得到筷子了guiMgr.setChopstickImage(id, chopstickNo);// 占用筷子chopsticks[chopstickNo].setUsed(true);System.out.println("Person[" + id + "] has got Chopstick["+ chopstickNo + "] at time:" + new Date());
}

请先忽略所有与guiMgr相关的代码,那是为此程序加上GUI界面的代码,与逻辑没有任何关系。

首先某个特定的筷子是竞争资源,只有它未被占用时才可持有,也就是上面的while语句。如果一直被Used,则一直wait。直到被notifyAll则可继续下面的代码,即把筷子占用chopsticks[chopstickNo].setUsed(true);

接下来是吃的动作

/**
* 吃几秒钟.
*/private void eating() {System.out.println("Person[" + id + "] is eating using Chopsticks["+ leftNo + "][" + rightNo + "]");try {// 得到了两只筷子,可以吃东西了guiMgr.setPersonEating(id);Thread.sleep(SLEEP_TIME);} catch (InterruptedException e) {e.printStackTrace();}// 吃完释放左右筷子synchronized (chopsticks[leftNo]) {// 释放筷子guiMgr.releaseChopstick(leftNo);chopsticks[leftNo].setUsed(false);// 唤醒其他需要此筷子的哲学家chopsticks[leftNo].notifyAll();}synchronized (chopsticks[rightNo]) {// 释放筷子guiMgr.releaseChopstick(rightNo);chopsticks[rightNo].setUsed(false);chopsticks[rightNo].notifyAll();}
}

吃饭大概几秒钟时间,然后把左右筷子释放,并唤醒等待该筷子的其他哲学家。至此,哲学家问题就搞定了。接下来看看GUI图像实现部分。

本例采用了组合的方式即PhilosopherDining中含有GuiManage的引用。GuiManage是专门用于转换哲学家问题到GUI图像显示的中间类,它又含有图像实现类JFrameGridLayout的引用,根据PhilosopherDining中Person实例传递的参数做判断,调用JFrameGridLayout暴露出的方法来控制GUI界面。从而剥离了业务逻辑与前端显示的耦合。

大体思路如下。我使用的是GridLayout,即网格布局。

布局的各组件如下。其中最外层是数字,表示坐标,灰色部分才是真正的布局区域,P表示哲学家,C表示筷子。

P0~P4分布在五个相对对称的位置;

筷子的位置因为会经常变化,所以使用复合数字及不同底色表示。其中

红色表示筷子的初始位置,即每个筷子未被任何人持有的情况下的位置;

蓝色表示筷子相对于其初始位置的右边;

黄色表示筷子相对于其初始位置的左边;

这时再看GuiManage中的下面常量就好理解了

/**
* 人的位置,固定的.
*/private static final Position[] personPositions = new Position[MAX];
static {personPositions[0] = new Position(0, 5);
personPositions[1] = new Position(4, 10);
personPositions[2] = new Position(9, 9);
personPositions[3] = new Position(9, 1);
personPositions[4] = new Position(4, 0);}/**
* 筷子位置,枚举了筷子三种状态的位置.*/private static final ChopstickPosition[] chopstickPositions = new ChopstickPosition[MAX];static {// 枚举五个筷子的十五种状态下对应的位置
chopstickPositions[0] = new ChopstickPosition(new int[][] { { 1, 6 }, { 3, 9 }, { 3, 7 } });
chopstickPositions[1] = new ChopstickPosition(new int[][] { { 5, 9 }, { 8, 9 }, { 6, 7 } });
chopstickPositions[2] = new ChopstickPosition(new int[][] { { 9, 8 }, { 9, 2 }, { 7, 5 } });
chopstickPositions[3] = new ChopstickPosition(new int[][] { { 8, 1 }, { 5, 1 }, { 6, 3 } });
chopstickPositions[4] = new ChopstickPosition(new int[][] { { 3, 1 }, { 1, 4 }, { 3, 3 } });

还有这段

/*** 根据筷子号码,及被谁持有设置筷子图片.* * @param id*            人的id* @param no*            筷子号码
*/
public void setChopstickImage(final int id, final int no) {Position p = null;String image = null;if (id % MAX == no) {p = chopstickPositions[no].getPosition(RIGHT_INDEX);image = getChopstickImage(no, RIGHT_INDEX);} else {p = chopstickPositions[no].getPosition(LEFT_INDEX);image = getChopstickImage(no, LEFT_INDEX);}setChopstickImage(no, p, image);
}

id % MAX == no则是相对于筷子原位置的右边,这是很好理解的。如现在是哲学家0持有0号筷子则0 % 5 == 0是成立的,则0号筷子处于C00 即(1,6)的位置,(1,6)则为chopstickPositions[0]的第0(RIGHT_INDEX的值)个元素,反正则是C01,这则是chopstickPositions[0]的第1(LEFT_INDEX的值)个元素。

理解了此处则整个画图程序也就基本理解了。

注:C00中第一个数字表示第0号筷子,第二个数字表示是RIGHT_INDEX、LEFT_INDEX或INIT_INDEX的其中一个值。

哲学家问题(图形化实现)相关推荐

  1. 晶体管逻辑芯片设计微缩图形化

    晶体管逻辑芯片设计微缩图形化 伴随着晶体管大小不断逼近原子的物理体积极限,传统摩尔定律下的2D微缩技术不再能同时改善芯片的性能.功率.面积成本和上市时间(即:PPACt),晶体管设计.互连微缩.图形化 ...

  2. centos7上的图形化界面svn客户端_Git实战一:图形客户端规范用法小讲

    git作为一款分布式版本管理工具,受到许多资深码农喜爱,我也刚好是其中一位. 百度上有许多介绍git安装教程.和svn的区别,这些都不再重复,好多也是介绍命令模式操作git,但是今天我要讲的是图形化操 ...

  3. fedora mysql默认密码忘记_Linux fedora 24 忘记密码图形化界面修改root密码的方法

    方法及其简单,只需要两步即可: 1.第一步: 打开终端,输入sudo su命令. –此处的密码为普通用户的密码,也就是开机时输入的密码. 2.第二步: 直接sudo passwd root就重置了ro ...

  4. gdb图形化调试工具总结

    gdb除了命令行方式等的调试之外,还有图形化的调试工具,下面列举一些供参考 1:insight 2: ddd 3: kgdb 4: xxgdb 其它的工具欢迎补充

  5. 利用VisualEsxtop工具图形化查看esxtop参数

    怎样使用VisualEsxtop工具 众多VMware的工程师都知道esxtop/rextop在进行故障排查.性能检测的场景中的重要性:一般而言我们都可以通过各种shell工具连接到ESXI主机,默认 ...

  6. 自制操作系统Antz(9)——实现内核 (下) 实现图形化界面

    Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...

  7. Java图形化界面设计——容器(JFrame)

    Java图形化界面设计--容器(JFrame) 程序是为了方便用户使用的,因此实现图形化界面的程序编写是所有编程语言发展的必然趋势,在命令提示符下运行的程序可以让我们了解java程序的基本知识体系结构 ...

  8. 四月青少年编程组队学习(图形化四级)Task05

    电子学会 软件编程(图形化)四级 组队学习 试题来源: 青少年软件编程(Scratch)等级考试试卷(四级)[2019.12] 青少年软件编程(Scratch)等级考试试卷(四级)[2020.06] ...

  9. 四月青少年编程组队学习(图形化四级)Task03

    电子学会 软件编程(图形化)四级 组队学习 试题来源: 青少年软件编程(Scratch)等级考试试卷(四级)[2019.12] 青少年软件编程(Scratch)等级考试试卷(四级)[2020.06] ...

最新文章

  1. 在 Linux 中创建和管理归档文件教程在 Linux 中创建和管理归档文件教程
  2. 电子科技大学计算机考研题,电子科技大学计算机科学与技术考研820历年真题
  3. Cpp 对象模型探索 / 成员初始化列表
  4. 计算机专业科普知识图文并茂,科普下计算机专业需要什么基础知识?
  5. Navicat工具导出mySQL数据库某个视图结构的.sql脚本
  6. php mysql 拼音首字母,Mysql应用MySQL查询汉字的拼音首字母实例教程
  7. C/C++混淆点-与
  8. 【论文阅读】基于未知传播模型的信息源检测问题 2017年AAAI国际先进人工智能协会
  9. Uinttest +excel结合使用--详细讲解
  10. java poi 页码,apache poi页码
  11. python showinfo函数_Python 函数
  12. html引入png不显示透明北京,完美解决透明png图片及透明png背景,兼容所有浏览器...
  13. MCE | 靶向 cGAS-STING 通路或可治疗渐冻症
  14. matlab彩色图像的R、G、B三个分量以灰色和彩色的形式显示
  15. 用计算机绘制函数图像数学大师,什么手机app可以画函数图像 能画函数图像的app推荐...
  16. Map使用对象作key
  17. 【Python】笨方法学Python学习笔记2
  18. macbook的appstore打不开的解决办法
  19. 年销近4亿只粽子,五芳斋冲刺“粽子第一股”,粽子一哥的月饼香吗?
  20. 人工智能前沿——AI技术在医疗领域的应用(二)

热门文章

  1. C++实现 数字游戏之拼出最大数
  2. PTA】{10-1 结构拓展实验,函数}6-3 求某学生8门课的平均分 (10 分)
  3. python将中文汉字转换成拼音
  4. word文档画笔添加后灰色无法启用!
  5. 微信公众号授权及关注
  6. 2.2 PB-ADV入网过程
  7. Java回炉学习(七)
  8. PJzhang:贷款逾期与失信被执行人
  9. 行稳致远,进而有为——2020年 XAG发展展望
  10. 荣耀路由2 虚拟服务器,华为荣耀路由器2怎么设置? | 192路由网