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. BRIEF 特征描述子

    Binary Robust Independent Elementary Features www.cnblogs.com/ronny 1. BRIEF的基本原理 我们已经知道SIFT特征采用了128 ...

  2. HDU 5787 K-wolf Number 数位DP

    K-wolf Number Problem Description   Alice thinks an integer x is a K-wolf number, if every K adjacen ...

  3. 接着上一篇 《Is WPF dead》

    最近美国的PM传来消息,说微软在收集开发者的意见,会对WPF进行改进,微软会主要在1) performance 2) interop 3) touch and 4) access to WinRT A ...

  4. Windows下MySQL zip版的简单安装

    1.下载MySQL-5.5.10-win32.zip的版本.2.解压到任意路径,比如"D:\Programm Files\".3.进入MySQL路径,复制my-small.ini为 ...

  5. 【框架】异步加载大量图片--ImageLoader

    public abstract class BaseImageLoaderProvider { public abstract void loadImage(Context ctx, ImageLoa ...

  6. 【POI word】使用POI实现对Word的读取以及生成

    项目结构如下: 那第一部分:先是读取Word文档 package com.it.WordTest; import java.io.FileInputStream; import java.io.Fil ...

  7. Android学习系列(38)--Android源码下载和编译

    前面多篇文章介绍到如何下载和编译Android或者CM源码,不过一直都是放在<拓展系列>里.随着学习的深入,android源码是非常有参考和学习价值,强烈推荐大家都去下载,编译,学习,所以 ...

  8. ajax上传后用超链接展示无法下载问题

    ajax插件上传后用超链接展示出来,但是点击超链接无法下载,最后发现是上传文件名为中文在作怪,于是修改了tomcat配置文件server.xml中的 <Connector port=" ...

  9. hadoop 分布式缓存

    Hadoop 分布式缓存实现目的是在所有的MapReduce调用一个统一的配置文件,首先将缓存文件放置在HDFS中,然后程序在执行的过程中会可以通过设定将文件下载到本地具体设定如下: public s ...

  10. iOS学习11之OC继承

    面向对象的三大特性:封装,继承,多态. 1.继承 继承既能保证类的完整,又能简化代码. 把公共的⽅法和实例变量写在⽗类⾥,⼦类只需要写⾃⼰独有的实例变量和⽅法即可. 继承是⾯向对象三⼤特性之⼀,合理的 ...