《Java-SE-第三十章》之哲学家就餐问题

news2024/11/28 20:51:07

前言

在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!”

博客主页:KC老衲爱尼姑的博客主页

博主的github,平常所写代码皆在于此

共勉:talk is cheap, show me the code

作者是爪哇岛的新手,水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


文章目录

  • 死锁
    • 哲学家就餐问题
      • 死锁复现
      • 解决办法

死锁

  当某个任务在等待另一个任务,而后者又等待别的任务,这样一直下去,直到这个链条上的任务又在等待第一个任务释放锁。这得到了一个任务之间互相等待的连续循环, 没有那个线程能继续,这称之为死锁。举个栗子,张三想要回家,当开门的时候,发现没钥匙,此时张三突然想起,屋子钥匙放在了车里面,而车的钥匙在房子里面,想要进入就得打开车子,想要打开车子,必须的进屋子,这就"死锁"了。

示例代码

public class DeadlockDemo {
    public static void main(String[] args) {
        Object A = new Object();
        Object B = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (A) {
                System.out.println("lock A");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (B) {
                    System.out.println("lock B");
                }
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (B) {
                System.out.println("lock B");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (A) {
                    System.out.println("lock A");
                }
            }
        });
        t2.start();
    }
}

通过使用jconsole观察两个线程的状态

在这里插入图片描述

通过观察可知都死锁了

哲学家就餐问题

  哲学家就餐问题由Edsger Dijkstra提出的,该问题是一个经典的死锁问题,该问题的基本描述中是指定五个哲学家。这些哲学家将花部分时间思考,花部分时间就餐。当他们思考的时候,不需要任何共享资源;但当他们就餐时,将使用有限数量的餐具。在问题的原始描述中,餐具是叉子。要吃到桌子中央盘子里的意大利面条需要用两把叉子,不过把餐具看成是筷子更合理;很明显,哲学家要就餐就需要两根筷子。问题中引入的难点是:作为哲学家,他们很穷,所以他们只能买五根筷子(更一般地讲,筷子和哲学家的数量相同)。他们围坐在桌子周围,每人之间放一根筷子。当一个哲学家要就餐的时候,这个哲学家必须同时得到左边和右边的筷子。上述问题会产生死锁的情况,当5个哲学家都拿起自己左或者右手手边的筷子,准备拿右手或者左手边的筷子时产生死锁现象。

在这里插入图片描述

代码演示

  1. 定义一个筷子类
public class Chopstick {
    private String name;

    public Chopstick(String name) {
        this.name = name;
    }
}
  1. 定义哲学家
public class Philosopher implements Runnable {
    /**
     * 左手筷子
     */
    private Chopstick left;
    /**
     * 右手筷子
     */
    private Chopstick right;
    /**
     * 名字
     */
    private String name;

    public Philosopher(Chopstick left, Chopstick right, String name) {
        this.left = left;
        this.right = right;
        this.name = name;
    }

    public void thinking() {
        System.out.println(this.name + " " + "thinking");

    }

    public void eating() {
        System.out.println(this.name + " " + "eating");
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            thinking();
            synchronized (this.right) {
                synchronized (this.left) {
                    eating();
                }
            }
        }
    }
}

死锁复现

import java.io.IOException;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DeadLockPhilosopher {
    public static void main(String[] args) throws InterruptedException, IOException {
        int size = 5;
        ExecutorService exec = Executors.newCachedThreadPool();
        Chopstick []  sticks = new Chopstick[size];
        for (int i = 0; i < sticks.length;i++){
            sticks[i] = new Chopstick(i+"号筷子");
        }
        for (int i = 0; i < size;i++) {
            exec.execute(new Philosopher(sticks[i], sticks[(i+1) % size],i+"号哲学家"));
        }
        TimeUnit.SECONDS.sleep(10);
        exec.shutdownNow();
    }
}

运行结果:

在这里插入图片描述

代码先是正常运行了一会,然后将就死锁了,是否死锁依旧用jconsole观察,观察结果如下图

在这里插入图片描述

解决办法

要修正死锁问题,你必须明白,当以下四个条件同时满足时,就会发生死锁:

  1. 互斥条件。任务使用的资源中至少有一个是不能共享的。这里,一根Chopstick一次就只能被一个Philosopher使用。
  2. 请求和保持,至少有一个任务它必须持有一个资源且正在等待获取一个当前被别的任务持有的资源。也就是说,要发生死锁,Philosopher必须拿着一根Chopstick并且等待另一根。
  3. 资源不能被任务抢占,任务必须把资源释放当作普通事件。Philosopher很有礼貌,他们不会从其他Philosopher那里抢Chopstick
  4. 必须有循环等待,这时,一个任务等待其他任务所持有的资源,后者又在等待另一个任务所持有的资源,这样一直下去,直到有一个任务在等待第一个任务所持有的资源,使得大家都被锁住。在DeadlockingDiningPhilosophers.java中,因为每个Philosopher都试图先得到右边的Chopstick,然后得到左边的Chopstick,所以发生了循环等待。

  因为要发生死锁的话,所有这些条件必须全部满足;所以要防止死锁的话,只需破坏其中一个即可。在程序中,防止死锁最容易的方法是破坏第4个条件。有这个条件的原因是每个Philosopher都试图用特定的顺序拿Chopstick:先右后左。正因为如此,就可能会发生“每个人都拿着右边的Chopstick,并等待左边的Chopstick”的情况,这就是循环等待条件。然而,如果最后一个Philosopher被初始化成先拿左边的Chopstick,后拿右边的Chopstick,那么这个Philosopher将永远不会阻止其右边的Philosopher拿起他们的Chopstick。

示例代码


import java.util.concurrent.*;

public class FixedDiningPhilosophers {
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        Chopstick[] sticks = new Chopstick[5];
        int size = 5;
        for (int i = 0; i < sticks.length; i++) {
            sticks[i] = new Chopstick(i + "号筷子");
        }
        for (int i = 0; i < sticks.length; i++) {
            //前四个哲学家
            if (i < (size - 1)) {
                exec.execute(new Philosopher(sticks[i], sticks[(i + 1)], i + "哲学家"));
            } else {
                exec.execute(new Philosopher(sticks[0], sticks[(i)], i + "哲学家"));
            }
        }
        TimeUnit.SECONDS.sleep(5);
        exec.shutdownNow();
    }
}

运行结果:
在这里插入图片描述

由此就解决了哲学家就餐问题中的死锁


各位看官如果觉得文章写得不错,点赞评论关注走一波!谢谢啦!。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/843627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mongodb-win32-x86_64-2008plus-3.4.24-signed.msi

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator>cd C:\MongoDB\Server\3.4\binC:\MongoDB\Server\3.4\bin>C:\MongoDB\Server\3.4\bin>mongod --help Options:General options:-h [ --help ] …

窥探系列之Mybatis-plus XML分页查询

mybatisPlus分页查询原理 searchCount字段控制是否查询总记录数 com.baomidou.mybatisplus.plugins.PaginationInterceptor 该插件拦截sql&#xff0c;如果searchCounttrue&#xff0c;则使用sql解析包jsqlparser根据原sql生成count语句&#xff0c;另外关键

面对裁员风险,我们该如何提升体能素质?——探讨年龄与体能的关系

文章目录 每日一句正能量前言你现在身体的体能状况如何&#xff1f;你有身体焦虑吗&#xff1f;如何保持规律性运动&#xff1f;你有哪些健康生活的好习惯&#xff1f;后记 每日一句正能量 当你看不到别人的缺点时&#xff0c;你就能从别人的行为、语言、思想中得到无限的智慧。…

数据结构 | 利用二叉堆实现优先级队列

目录 一、二叉堆的操作 二、二叉堆的实现 2.1 结构属性 2.2 堆的有序性 2.3 堆操作 队列有一个重要的变体&#xff0c;叫作优先级队列。和队列一样&#xff0c;优先级队列从头部移除元素&#xff0c;不过元素的逻辑顺序是由优先级决定的。优先级最高的元素在最前&#xff…

【程序环境与预处理玩转指南】

本章重点&#xff1a; 程序的翻译环境 程序的执行环境 详解&#xff1a;C语言程序的编译链接 预定义符号介绍 预处理指令 #define 宏和函数的对比 预处理操作符#和##的介绍 命令定义 预处理指令 #include 预处理指令 #undef 条件编译 1. 程序的翻译环境和执行环境 在…

Java基础入门篇——IntelliJ IDEA下载与安装(四)

IntelliJ IDEA是一款流行的Java集成开发环境&#xff08;IDE&#xff09;&#xff0c;由JetBrains公司开发。你可以按照以下步骤下载和安装IntelliJ IDEA&#xff1a; 一、下载 访问官方网站&#xff1a;打开浏览器&#xff0c;访问JetBrains的官方网站。你可以直接在搜索引擎…

SAP MM学习笔记15-物料调达中的Master数据(2)-品目Master

SAP中做一个购买发注的时候&#xff0c;涉及到以下Master数据&#xff1a; 1&#xff0c;仕入先Master&#xff08;供应商&#xff09;&#xff1a;跟谁买 2&#xff0c;品目Master&#xff08;物料&#xff09;&#xff1a;买什么 3&#xff0c;购买情报&#xff1a;什么价…

MONGODB ---- Austindatabases 历年文章合集

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

过滤器和拦截器的六大区别

平时觉得简单的知识点&#xff0c;但通常都不会太关注细节&#xff0c;一旦被别人问起来&#xff0c;反倒说不出个所以然来。真的就是一看就会一说就废。下面带大家一起结合实践来区分过滤器和拦截器吧~ 通俗理解&#xff1a; &#xff08;1&#xff09;过滤器&#xff08;Fil…

CMake 3.13.4 or higher is required. You are running version 3.10.2

ubuntu 安装 cmake&#xff0c;但是apt安装的版本太低&#xff0c;需要其他安装方法。 参考视频 https://www.youtube.com/watch?v_yFPO1ofyF0 以下是对视频内容的提炼&#xff0c;就两点 1、下载需要版本的sh文件&#xff1b;2、安装 一、下载需要版本的sh文件 https://cma…

【ArcGIS Pro二次开发】(58):数据的本地化存储

在做村规工具的过程中&#xff0c;需要设置一些参数&#xff0c;比如说导图的DPI&#xff0c;需要导出的图名等等。 每次导图前都需要设置参数&#xff0c;虽然有默认值&#xff0c;但还是需要不时的修改。 在使用的过程中&#xff0c;可能会有一些常用的参数&#xff0c;希望…

shell 入门练习小记

一、hello world #!/bin/bash echo "Hello World !"#! 为约定的标记&#xff0c;告诉系统这个脚本需要什么解释器执行&#xff0c;后接绝对路径 /bin/bash 表示期望 bash去解析并运行shell echo用于向窗口输出文本 chmod x ./test.sh #给脚本赋执行权限 ./test.sh …

Leetcode-每日一题【剑指 Offer 10- II. 青蛙跳台阶问题】

题目 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 答案需要取模 1e97&#xff08;1000000007&#xff09;&#xff0c;如计算初始结果为&#xff1a;1000000008&#xff0c;请返回 1。 示例 1&#xff1a; 输…

Linux命令200例:tr用于对输入的文本进行字符转换、删除、替换等

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

龙架构 Arch Linux 发行版发布

导读近日&#xff0c;龙架构 Arch Linux 发行版官方网站宣布结束 beta 状态&#xff0c;正式支持龙架构 (LoongArch)。 Arch Linux 是一种轻量级、可定制、灵活的 Linux 操作系统。作为一款简单、现代、开放的操作系统&#xff0c;Arch Linux 旨在基于 “KISS 原则”&#xff0…

2020年12月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题 第1题 执行语句print(1010.0)的结果为&#xff1f; A&#xff1a;10 B&#xff1a;10.0 C&#xff1a;True D&#xff1a;False 正确的答案是 C&#xff1a;True。 解析&#xff1a;在Python中&#xff0c;比较运算符 “” 用于比较两个值是否相等。在这个特…

解释器模式(Interpreter)

解释器模式是一种行为设计模式&#xff0c;可以解释语言的语法或表达式。给定一个语言&#xff0c;定义它的文法的一种表示&#xff0c;然后定义一个解释器&#xff0c;使用该文法来解释语言中的句子。解释器模式提供了评估语言的语法或表达式的方式。 Interpreter is a behav…

以太网ICMP协议(九)

目录 一、概述 二、ICMP消息类型 2.1 ICMP类型0和类型8&#xff1a;Ping功能 2.2 ICMP类型3&#xff1a;目标不可达 2.3 ICMP类型5&#xff1a;重定向 2.4 ICMP类型11&#xff1a;超时 三、报文格式 一、概述 由于IP协议是不可靠的通信协议&#xff0c;需要有其他协议的…

线程池的使用案例一

一、配置线程池 1、不推荐的方式 ExecutorService executorService Executors.newFixedThreadPool(); // 创建⼀个固定⼤⼩的线程池&#xff0c;可控制并发的线程数&#xff0c;超出的线程会在队列中等待&#xff1b; ExecutorService executorService Executors.newCache…

无监督SLAM框架

因为之前做过双目立体匹配相关项目&#xff0c;当时就了解到有一些无监督方法。最近涉及到SLAM相关项目&#xff0c;想到理论上可以用photo loss无监督学习光流和pose&#xff0c;因此查看了有没有SLAM无监督的相关论文。发现确实有几篇论文。但总感觉设计的不是很好&#xff0…