哲学家进餐

哲学家进餐避免死锁

进餐条件

5 个沉默寡言的哲学家围坐在圆桌前,每人面前一盘意面。叉子放在哲学家之间的桌面上。(5 个哲学家,5 根叉子)

所有的哲学家都只会在思考和进餐两种行为间交替。哲学家只有同时拿到左边和右边的叉子才能吃到面,而同一根叉子在同一时间只能被一个哲学家使用。每个哲学家吃完面后都需要把叉子放回桌面以供其他哲学家吃面。只要条件允许,哲学家可以拿起左边或者右边的叉子,但在没有同时拿到左右叉子时不能进食。

假设面的数量没有限制,哲学家也能随便吃,不需要考虑吃不吃得下。

设计一个进餐规则(并行算法)使得每个哲学家都不会挨饿;也就是说,在没有人知道别人什么时候想吃东西或思考的情况下,每个哲学家都可以在吃饭和思考之间一直交替下去。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-dining-philosophers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

死锁条件:5个哲学家同时拿起左边叉子

PS:死锁的 4个必要条件:

  • 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
  • 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
  • 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
  • 循环等待条件: 若干进程间形成首尾相接循环等待资源的关系。

作者:gfu
链接:https://leetcode-cn.com/problems/the-dining-philosophers/solution/1ge-semaphore-1ge-reentrantlockshu-zu-by-gfu/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解决方式:
1.同时拿起两边叉子,否则不拿
2.顺序拿起左边叉,同时进餐人数不超过四人

方案一:同时拿起两边叉子,否则不拿
代码如下:

void getFork(int i){
        Semaphore left=semaphores[i];
        Semaphore right=null;

        if(i==4){
            right=semaphores[0];
        }else {
            right=semaphores[i+1];
        }

        if(left.tryAcquire()){
            System.out.println(i+"拿到叉子左:"+i);
            if(right.tryAcquire()){
                System.out.println(i+"拿到叉子右:"+String.valueOf(i+1));

                execute(i);


                right.release();
                left.release();
                System.out.println(i+"释放两个叉子");
            }else {
                System.out.println(i+"释放叉子左:"+i);
                left.release();

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }else {

        }
        int priority =Thread.currentThread().getPriority();

        Thread.currentThread().setPriority(2);

        Thread.yield();
        System.out.println(priority);

    }

方案二
顺序拿起左边叉,同时进餐人数不超过四人
1.设置拿叉子顺序,(除非拿起所有叉子,否则不释放锁,一直阻塞)

void getFork2(int i){
        Semaphore left=semaphores[i];
        Semaphore right=null;

        if(i==4){
            right=semaphores[0];
        }else {
            right=semaphores[i+1];
        }

        try {
            left.acquire();
            System.out.println(i+"拿到叉子左:"+i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {

            right.acquire();
            System.out.println(i+"拿到叉子右:"+i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        execute(i);
        left.release();
        right.release();
    }

2.利用线程池保证同时执行的线程不超过四个

  ExecutorService executorService= Executors.newFixedThreadPool(5);

测试代码如下

package threads;

import org.junit.Test;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description:哲学家进餐
 * @author: HYW
 * @create: 2020-01-03 15:08
 */
public class DiningPhilosophers {
    int num=5;

    private Semaphore[] semaphores=new Semaphore[4];

    public DiningPhilosophers() {
        for (int i = 0; i < num; i++) {
            //每只叉子只有1个
            semaphores[i] = new Semaphore(1);
        }

    }




    void eat(int i){
        i=i-1;
        while(true){
           //方案一
           //getFork(i);
           //方案二
            getFork2(i);
            Thread.yield();
            /*try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/

        }
    }
    void getFork2(int i){
        Semaphore left=semaphores[i];
        Semaphore right=null;

        if(i==4){
            right=semaphores[0];
        }else {
            right=semaphores[i+1];
        }

        try {
            left.acquire();
            System.out.println(i+"拿到叉子左:"+i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {

            right.acquire();
            System.out.println(i+"拿到叉子右:"+i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        execute(i);
        left.release();
        right.release();
    }
    void getFork(int i){
        Semaphore left=semaphores[i];
        Semaphore right=null;

        if(i==4){
            right=semaphores[0];
        }else {
            right=semaphores[i+1];
        }

        if(left.tryAcquire()){
            System.out.println(i+"拿到叉子左:"+i);
            if(right.tryAcquire()){
                System.out.println(i+"拿到叉子右:"+String.valueOf(i+1));

                execute(i);


                right.release();
                left.release();
                System.out.println(i+"释放两个叉子");
            }else {
                System.out.println(i+"释放叉子左:"+i);
                left.release();

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }else {

        }
        int priority =Thread.currentThread().getPriority();

        Thread.currentThread().setPriority(2);

        Thread.yield();
        System.out.println(priority);

    }

    void execute(int i){
        System.out.println("哲学家"+ i+" 吃饭");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
    public static void main(String[] args) {
        DiningPhilosophers demo=new DiningPhilosophers();
        ExecutorService executorService= Executors.newFixedThreadPool(4);

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                demo.eat(1);
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                demo.eat(2);
            }
        });

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                demo.eat(3);
            }
        });

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                demo.eat(4);
            }
        });

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                demo.eat(5);
            }
        });

        executorService.shutdown();
    }
}

注意

线程池会把超过最大线程数的任务,放在队列种等待,所以第五位哲学家只有在前四位哲学家的线程吃完(停止)后,才可以吃饭。
改进方式,增加信号量,Semaphore eatnerNum= new Semaphore(4);
保证同时只有四人进餐

发布了21 篇原创文章 · 获赞 6 · 访问量 9317

猜你喜欢

转载自blog.csdn.net/qq1032350287/article/details/103823898
今日推荐