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. 第二十五篇:在SOUI中做事件分发处理

    不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分 ...

  2. 如何在Salesforce中进行代码开发

    两种方式: 1):用Salesforce自带的在线开发模式 Setup --> App Setup --> Develop --> than you can select 'Page ...

  3. 德飞莱STM32单片机学习(一)——下载环境搭建

    一.下载驱动安装. 1.手动打开CH341 文件夹(驱动程序文件夹内) ,双击安装驱动 2. 尼莫M3S 开发硬件设置 硬件需要做到以下2 点:1. USB插入USB1(COM),打开电源开关J14( ...

  4. 在MySQL中存储大文件

    我们的目标:把一首mp3保存到MySQL数据库中! 由于MySQL默认当存入的数据太大时会抛异常,所以应在my.ini中添加如下配置!max_allowed_packet=10485760,这样,可以 ...

  5. 开发Portlet第一步:如何基于Crystal开发静态Portlet?

    当团队需要基于Crystal开发Porltet时,分为以下三部: 基于Crystal开发静态Portlet 基于将静态Portlet修改为基于测试数据的动态Portlet 将动态Portlet与动态数 ...

  6. Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)

    使用命令关闭占用80端口的程序 sudo fuser -k 80/tcp

  7. 廖雪峰js教程笔记 2

    arguments JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数.arguments类似Array但它不是一个Arr ...

  8. css3 -- 属性选择器

    属性选择器: 1.CSS属性选择器 属性选择器E[attr="value"]{} 包含属性选择器E[attr~="value"]{} 2.CSS3的新属性选择器 ...

  9. Block与代理的使用

    本人其实是比较喜欢用Block的,因为用block写出来的代码,让我感觉代码要紧凑一些,看起来的时候,思路要清晰些,所以这估计也就是现在block将要代替代理的原因所在吧! 下面,直接进入主题: 一. ...

  10. jQuery下操作dropdownlist

    dropdownlist呈现到html中如下: <select id="ddlOrg" name="ddlOrg">     <option ...