哲学家进餐问题

1965年,荷兰计算机科学家图灵奖得主Edsger Wybe Dijkstra提出并解决了一个他称之为哲学家进餐的同步问题。这个问题可以简单地描述如下:五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一盘通心粉。由于通心粉很滑,所以需要两把叉子才能夹住。相邻两个盘子之间放有一把叉子如下图所示。哲学家的生活中有两种交替活动时段:即吃饭和思考。当一个哲学家觉得饿了时,他就试图分两次去取其左边和右边的叉子,每次拿一把,但不分次序。如果成功地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。   把上面问题中的哲学家换成线程,把叉子换成竞争的临界资源,上面的问题就是线程竞争资源的问题。如果没有经过精心的设计,系统就会出现死锁、活锁、吞吐量下降等问题

Paste_Image.png
package threadTest;

import java.util.concurrent.Semaphore;

public class test01 {
     public static void main(String[] args) {
            String[] names = { "骆昊", "王大锤", "张三丰", "杨过", "李莫愁" };   // 5位哲学家的名字
//        ExecutorService es = Executors.newFixedThreadPool(AppContext.NUM_OF_PHILO); // 创建固定大小的线程池
//        for(int i = 0, len = names.length; i < len; ++i) {
//            es.execute(new Philosopher(i, names[i]));   // 启动线程
//        }
//        es.shutdown();
            for(int i = 0, len = names.length; i < len; ++i) {
                new Thread(new Philosopher(i, names[i])).start();
            }
        }
}

class AppContext{
    public static final int NUM_OF_FORKS=5; //叉子数量(资源)
    public static final int NUM_OF_PHILO=5; //哲学家数量(线程)
    
    public static Semaphore[] forks;    //叉子的信号量
    public static Semaphore counter;    //哲学家的信号量

    static{
        forks=new Semaphore[NUM_OF_FORKS];
        
        for(int i=0,len=forks.length;i<len;i++){
            forks[i]=new Semaphore(1);  //每个叉子的信号量为1
        }
        
        counter=new Semaphore(NUM_OF_PHILO-1);  //如果有n个哲学家,最多只允许n-1人同时取叉子
    }
    
    /**
     * 取得叉子
     * @param index 第几个哲学家
     * @param leftFirst 是否先取得左边的叉子
     * @throws InterruptedException
     */
    public static void putOnFork(int index,boolean leftFirst)throws InterruptedException{
        if(leftFirst){
            forks[index].acquire();
            forks[(index+1)%NUM_OF_PHILO].acquire();
        }else{
            forks[(index+1)%NUM_OF_PHILO].acquire();
            forks[index].acquire();
        }
        
    }
    
    /**
     * 放回叉子
     * @param index 第几个哲学家
     * @param leftFirst 是否先放回左边的叉子
     * @throws InterruptedException
     */
    public static void putDownFork(int index,boolean leftFirst)throws InterruptedException{
        if(leftFirst){
            forks[index].release();
            forks[(index+1)%NUM_OF_PHILO].release();
        }else{
            forks[(index+1)%NUM_OF_PHILO].release();
            forks[index].release();
        }
        
    }
    
}

/**
 * 哲学家
 *
 */
class Philosopher implements Runnable {
    private int index;      // 编号
    private String name;    // 名字

    public Philosopher(int index, String name) {
        this.index = index;
        this.name = name;
    }
    @Override
    public void run() {
        while(true) {
            try {
                AppContext.counter.acquire();
                boolean leftFirst = index % 2 == 0;
                AppContext.putOnFork(index, leftFirst);
                System.out.println(name + "正在吃意大利面(通心粉)...");   // 取到两个叉子就可以进食
                AppContext.putDownFork(index, leftFirst);
                AppContext.counter.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}











最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 问题描述 一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生精力用...
    saviochen阅读 2,983评论 1 8
  • 编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的...
    jackfrued阅读 8,497评论 5 85
  • 这是以前写的一篇文章,今天发布出来该问题涉及多线程的内容,可以看我的这篇文章 POSIX多线程初步GitHub 地...
    南山脚下一棵树阅读 4,375评论 0 1
  • 失恋两个月了,很庆幸他跟我不在一个朋友圈。 我们交往了三年,朋友圈却没有什么太大的重合,他的朋友我认识几个。我的朋...
    路中间的姑娘阅读 254评论 0 0
  • SYN:同步标志。ACK:确认标志。FIN: 结束标志。 三次握手,建立Tcp连接。 例子一:比如在红军时代,A连...
    雀知安阅读 371评论 1 0