16.3 In the famous dining philosophers problem, a bunch of philosophers are sitting around a circular table with one chopstick between each of them. A philosopher needs both chopsticks to eat, and always picks up the left chopstick before the right one. A deadlock could potentially occur if all the philosophers reached for the left chopstick at the same time. Using threads and locks, implement a simulation of the dining philosophers problem that prevents deadlocks.

经典的哲学家聚餐问题,说是有一堆哲学家围着一个圆桌子坐着吃饭,每两个人之间都有一根筷子,每个人吃饭需要都需要左右两边的筷子,而且是先拿起左边的筷子,再拿右边的筷子,那么如果当所有的哲学家都拿着左边的筷子,那么就会产生死锁的情况。如果我们先不考虑死锁的问题,先来实现这个问题。我们可以把每个哲学家都当做一个线程,然后筷子被哲学家拿起后可以调用锁,当被放下后调用解锁,参见代码如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class Chopstick {
private Lock lock;
public Chopstick() {
lock = new ReentrantLock();
}
public void pickUp() {
lock.lock();
}
public void putDown() {
lock.unlock();
}
} public class Philosopher extends Thread {
private final int maxPause = 100;
private int bites = 10;
private Chopstick left;
private Chopstick right;
private int index; public Philosopher(int i, Chopstick left, Chopstick right) {
this.left = left;
this.right = right;
} public void eat() {
System.out.println("Philosopher" + index + ": start eating");
pickUp();
chew();
putDown();
System.out.println("Philosopher " + index + ": done eating");
} public void pickUp() {
pause();
left.pickUp();
pause();
right.pickUp();
} public void chew() {
System.out.println("Philosopher " + index + ": eating");
pause();
} public void pause() {
try {
int pause = (int)(Math.random() * maxPause);
Thread.sleep(pause);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void putDown() {
left.putDown();
right.putDown();
} public void run() {
for (int i = 0; i < bites; ++i) {
eat();
}
}
} public class j {
public static int size = 3; public static int leftOf(int i) {
return i;
} public static int rightOf(int i) {
return (i + 1) % size;
} public static void main(String[] args) {
Chopstick[] chopsticks = new Chopstick[size + 1];
for (int i = 0; i < size + 1; ++i) {
chopsticks[i] = new Chopstick();
} Philosopher[] philosophers = new Philosopher[size];
for (int i = 0; i < size; ++i) {
Chopstick left = chopsticks[leftOf(i)];
Chopstick right = chopsticks[rightOf(i)];
philosophers[i] = new Philosopher(i, left, right);
} for (int i = 0; i < size; ++i) {
philosophers[i].start();
}
}
}

上面的代码在执行中基本都会陷入死循环,因为发生了死锁的情况,所以我们应该想机制来避免死锁的发生,那么怎么做呢,我们首先想想死锁是怎么形成的,是因为每个人都拿着左边的筷子不放,又无法拿到右边的筷子,所以就一直僵持着,那么我们换个思路想想,如果每个人在拿了左筷子,发现没法取得右筷子后,就把左筷子放下,这样就可以避免死锁的形成。那么我们在Chopstik类中的pickUp函数中就应该使用tryLock()来代替lock,这样只有在有左筷子的时候才能锁上左筷子,而且在Philosopher类中的pickUp函数中,先判断能不能拿左筷子,不能拿直接返回false,能拿的话再来看能不能拿右筷子,不能拿的话,先把左筷子放下,再返回false,能拿的话返回true。这样在eat函数中先看pickUp是否能返回true,能返回的话再继续运行之后的东西,参见代码如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class Chopstick {
private Lock lock;
public Chopstick() {
lock = new ReentrantLock();
}
public boolean pickUp() {
return lock.tryLock();
}
public void putDown() {
lock.unlock();
}
} public class Philosopher extends Thread {
private final int maxPause = 100;
private int bites = 10;
private Chopstick left;
private Chopstick right;
private int index; public Philosopher(int i, Chopstick left, Chopstick right) {
index = i;
this.left = left;
this.right = right;
} public void eat() {
System.out.println("Philosopher" + index + ": start eating");
if (pickUp()) {
chew();
putDown();
System.out.println("Philosopher " + index + ": done eating");
} else {
System.out.println("Philosopher " + index + ": gave up on eating");
}
} public boolean pickUp() {
pause();
if (!left.pickUp()) {
return false;
}
pause();
if (!right.pickUp()) {
left.putDown();
return false;
}
pause();
return true;
} public void chew() {
System.out.println("Philosopher " + index + ": eating");
pause();
} public void pause() {
try {
int pause = (int)(Math.random() * maxPause);
Thread.sleep(pause);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void putDown() {
left.putDown();
right.putDown();
} public void run() {
for (int i = 0; i < bites; ++i) {
eat();
}
}
} public class j {
public static int size = 3; public static int leftOf(int i) {
return i;
} public static int rightOf(int i) {
return (i + 1) % size;
} public static void main(String[] args) {
Chopstick[] chopsticks = new Chopstick[size + 1];
for (int i = 0; i < size + 1; ++i) {
chopsticks[i] = new Chopstick();
} Philosopher[] philosophers = new Philosopher[size];
for (int i = 0; i < size; ++i) {
Chopstick left = chopsticks[leftOf(i)];
Chopstick right = chopsticks[rightOf(i)];
philosophers[i] = new Philosopher(i, left, right);
} for (int i = 0; i < size; ++i) {
philosophers[i].start();
}
}
}

CareerCup All in One 题目汇总

[CareerCup] 16.3 Dining Philosophers 哲学家聚餐问题的更多相关文章

  1. 第4章 同步控制 Synchronization ---哲学家进餐问题(The Dining Philosophers)

    哲学家进餐问题是这样子的:好几位哲学家围绕着餐桌坐,每一位哲学家要么思考,要么等待,要么就吃饭.为了吃饭,哲学家必须拿起两支筷子(分放于左右两端).不幸的是,筷子的数量和哲学家相等,所以每支筷子必须由 ...

  2. [CareerCup] 16.6 Synchronized Method 同步方法

    16.6 You are given a class with synchronized method A and a normal method B. If you have two threads ...

  3. [CareerCup] 16.5 Semphore 信号旗

    16.5 Suppose we have the following code:public class Foo { public Foo() { . . . } public void first( ...

  4. [CareerCup] 16.4 A Lock Without Deadlocks 无死锁的锁

    16.4 Design a class which provides a lock only if there are no possible deadlocks. 有很多方法可以避免死锁的发生,一个 ...

  5. [CareerCup] 16.2 Measure Time in a Context Switch 测量上下文转换的时间

    16.2 How would you measure the time spent in a context switch? 上下文转换发生在两个进程之间,比如让一个等待进程进入执行和让一个运行进程进 ...

  6. [CareerCup] 16.1 Thread and Process 线程和进程

    16.1 What's the difference between a thread and a process? 进程Process是程序执行时的一个实例.一个进程是被分配系统资源的独立单元,每个 ...

  7. CareerCup All in One 题目汇总

    Chapter 1. Arrays and Strings 1.1 Unique Characters of a String 1.2 Reverse String 1.3 Permutation S ...

  8. 代码整洁之道Clean Code笔记

    @ 目录 第 1 章 Clean Code 整洁代码(3星) ?为什么要整洁的代码 ?什么叫做整洁代码 第 2 章 Meaningful Names 有意义的命名(3星) 第 3 章 Function ...

  9. 【转】Multithreaded Python Tutorial with the “Threadworms” Demo

    The code for this tutorial can be downloaded here: threadworms.py or from GitHub. This code works wi ...

随机推荐

  1. Android三种基本的加载网络图片方式(转)

    Android三种基本的加载网络图片方式,包括普通加载网络方式.用ImageLoader加载图片.用Volley加载图片. 1. [代码]普通加载网络方式 ? 1 2 3 4 5 6 7 8 9 10 ...

  2. Ring3无敌进程让你的进程变得和smss.exe一样支持64

    本帖最后由 奋斗丶小Z 于 2016-6-6 13:39 编辑 此函数可以启用或关闭开启之后变得和系统进程一样被杀系统直接蓝屏系统进程也是此函数实现的上图 可以用于进程保护 <ignore_js ...

  3. WEB前端知识体系脑图

    说在开始的话: 我上大学那会,虽说主要是学Java语言,但是web前端也稍微学了一些,那时候对前端也没多在意,因为涉入的不深,可以搞一个差不多可以看的界面就可以了,其他也没过多在意. 因为稍微了解一点 ...

  4. 滑动listview隐藏和显示顶部布局

    需求: 1.listview向下滑动时,隐藏顶部布局 2.listview向上滑动到最上面,显示顶部布局 3.顶部布局的隐藏和显示有过渡效果 4.第一次加载listview时,顶部不要隐藏 布局: 注 ...

  5. 【JSON 注解】JSON循环引用1-----Jackson常用注解介绍 eq:@JsonIgnore

    循环引用:实体A与实体B有关系,A中有B作为字段,B中有A作为一个字段.查询A对象后,将A对象转化为JSON格式数据时,会因为序列化过程中导致A中有B字段,B字段中又有A,这样就引起了循环引用的问题! ...

  6. ExpandableListView 里面嵌套GridView实现高度自适应

    很早之前做过一个商城的app 也是第一次做安卓. 实现的效果如下: 因为一开始做安卓,很多写的代码都不规范,在下面上代码的地方,还请高手指点(勿喷,楼主是自尊心很强的屌丝) 这个效果要解决2个大问题, ...

  7. java中的三种取整函数

        舍掉小数取整:Math.floor(3.5)=3 四舍五入取整:Math.rint(3.5)=4 进位取整:Math.ceil(3.1)=4

  8. maven会报Could not transfer artifact xxx错误

    需要在你的eclipse更新一下maven的包 如下:

  9. Nginx支持多站点配置小结

    如何配置 web 服务器才能在一个 VPS 上放置多个网站/博客呢?如何通过一个 IP 访问多个站点/域名呢?这是大多数 web 服务器支持的 virtual hosting 功能.即一个IP对应多个 ...

  10. 从Sql server 2008获取表字段属性信息,注释信息

    select   b.[value] from sys.columns a left join sys.extended_properties b on a.object_id=b.major_id  ...