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. 10g ASM下修改control file的位置

    1.查看位置以及name是否正确 SQL> sho parameter name NAME TYPE VALUE ------------------------------------ --- ...

  2. 禁用编译器自动生成的函数(Effective C++之06)

    如果想让你的类定义出来的对象是独一无二的,即对象无法被复制,或者使用赋值操作符赋给另外一个对象,那么最好的方法就是禁用拷贝构造函数和赋值操作符.下面介绍几种禁用的方法.(方法来自Effective C ...

  3. 利用Aspose.Word控件和Aspose.Cell控件,实现Word文档和Excel文档的模板化导出

    我们知道,一般都导出的Word文档或者Excel文档,基本上分为两类,一类是动态生成全部文档的内容方式,一种是基于固定模板化的内容输出,后者在很多场合用的比较多,这也是企业报表规范化的一个体现. 我的 ...

  4. 两个本地(localhost)html文件之间的传值

    什么是iframe? iframe 元素会创建包含另外一个文档的内联框架(即行内框架).可以理解为把iframe解释成“浏览器中的浏览器“ 在IE中: document.frames[i].docum ...

  5. ios编码转换 国标 UTF-8

    我们知道,使用NSURLConnection的代理方法下载网页,存到一个NSData中, NSMutableData *pageData; [pageData appendData:data]; 如果 ...

  6. 汇编指令CLI/STI

    CLI禁止中断发生STL允许中断发生 这两个指令只能在内核模式下执行,不可以在用户模式下执行:而且在内核模式下执行时,应该尽可能快的恢复中断,因为CLI会禁用硬件中断,若长时间禁止中断会影响其他动作的 ...

  7. Redis 的 5 个常见使用场景

    2015-07-22 23:31:46 本文由 伯乐在线 - 刘晓鹏 翻译,黄利民 校稿.未经许可,禁止转载!英文出处:Joe Engel.欢迎加入翻译组. 在这篇文章中,我们将阐述 Redis 最常 ...

  8. windows下配置python库

    安装easy_install: 下载ez_setup.py文件,命令行执行python ez_setup.py; 将python文件夹下的Scripts文件夹加入到系统path路径: 检查easy_i ...

  9. opacity与rgba

    background: rgba(255,255,255,0.6);容器本身透明度变化,它包含的子容器的透明度不变. opacity:0.6;容器及容器包含的子容器的透明度都会发生变化.

  10. Eclipse: The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path

    Link: http://stackoverflow.com/questions/22756153/the-superclass-javax-servlet-http-httpservlet-was- ...