哲学家就餐问题(Java实现信号量和PV操作)

哲学家就餐是经典的PV操作。

一个哲学家同时拿起左边的筷子和右边的筷子进行就餐,每一个哲学家都会等待右边的筷子,具备了死锁问题之一的循环等待。

基础的哲学家就餐问题代码

在Java中,Semaphore 是一个用于控制对某个资源的访问的同步工具。它主要用于管理对有限资源的访问,确保在多线程环境中安全地控制资源的使用。

  • 信号量Semaphore 是一个计数信号量,维护一个计数器,表示可用资源的数量。
  • 获取与释放:线程可以通过 acquire() 方法获取一个许可,当资源可用时,计数器减一;如果没有可用资源,线程会被阻塞。释放资源时,使用 release() 方法,计数器加一。
  • acquire()就是p操作,获取资源。
  • release()就是v操作,用来释放资源。
import java.util.Arrays;
import java.util.concurrent.Semaphore;public class PhilosopherMeal extends Thread {private static String name = "哲学家";private int philosopherNum; //哲学家编号public static Semaphore[] semaphores = new Semaphore[5];public PhilosopherMeal(int philosopherNum) {//调用父类的Thread创建线程super(PhilosopherMeal.name + String.valueOf(philosopherNum));this.philosopherNum = philosopherNum;}@Overridepublic void run() {try {semaphores[this.philosopherNum].acquire();  //获取锁Thread.sleep((long) (Math.random() * 1));   //拿起筷子的时间,会发生死锁//acquire(): 获取一个许可。如果信号量的许可已经被其他线程占用,那么当前线程会阻塞,直到有许可可用。semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].acquire();System.out.println(this.getName() + "获取到了筷子" + String.valueOf(this.philosopherNum) +"和" + String.valueOf(this.getRightSemaphoreIndex(this.philosopherNum)) + "开始吃饭了");} catch (Exception e) {e.printStackTrace();} finally {//释放一个许可,意味着当前线程已不再占用资源,其他线程可以继续使用该资源。semaphores[(this.philosopherNum)].release();semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].release();}}//哲学家拿起右边的筷子吃饭private int getRightSemaphoreIndex(int philosopherNum) {return (philosopherNum - 1 < 0) ? semaphores.length - 1 : philosopherNum - 1;}public static void main(String[] args) {// Arrays.fill(semaphores,new Semaphore(1));for (int i = 0; i < semaphores.length; i++) {semaphores[i] = new Semaphore(1);}for (int i = 0; i < 5; i++) {new PhilosopherMeal(i).start();}}
}

发生死锁

没有发生死锁

解决方案

1.打破死锁的条件之一 循环条件等待,我们可以破坏循环的条件从而来解决死锁。

让奇数的筷子先拿左边的筷子,后拿右边的筷子。

偶数的筷子先拿右边的筷子,后那左边的筷子,这样就可以解决死锁的问题。破快了相互之间循环等待的条件。

@Override
public void run() {try {int n = this.philosopherNum; //拿到哲学家的编号if (n % 2 == 1) {  //奇数的先拿左边筷子 偶数拿右边semaphores[this.philosopherNum].acquire();  //获取锁Thread.sleep((long) (1000));   //拿起筷子的时间,会发生死锁semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].acquire();} else {semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].acquire();Thread.sleep((long) (1000));   //拿起筷子的时间,会发生死锁semaphores[this.philosopherNum].acquire();  //获取锁}//acquire(): 获取一个许可。如果信号量的许可已经被其他线程占用,那么当前线程会阻塞,直到有许可可用。System.out.println(this.getName() + "获取到了筷子" + String.valueOf(this.philosopherNum) +"和" + String.valueOf(this.getRightSemaphoreIndex(this.philosopherNum)) + "开始吃饭了");} catch (Exception e) {e.printStackTrace();} finally {//释放一个许可,意味着当前线程已不再占用资源,其他线程可以继续使用该资源。semaphores[(this.philosopherNum)].release();semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].release();}
}

2.最多只能让四个哲学家同时拿起筷子,这样就保证了一定有一个哲学家可以拿到筷子。这样就不会发生死锁。

    private static Semaphore count = new Semaphore(4);
@Override
public void run() {try {count.acquire(); //获取countsemaphores[this.philosopherNum].acquire();  //获取锁Thread.sleep(1000);semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].acquire();System.out.println(this.getName() + "获取到了筷子" + String.valueOf(this.philosopherNum) +"和" + String.valueOf(this.getRightSemaphoreIndex(this.philosopherNum)) + "开始吃饭了");} catch (Exception e) {e.printStackTrace();} finally {//释放一个许可,意味着当前线程已不再占用资源,其他线程可以继续使用该资源。semaphores[(this.philosopherNum)].release();semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].release();count.release();}
}

3 拿起左边筷子和右边筷子不是一个原子性的操作,我们可以加一个全局的锁,让拿左边筷子和右边的筷子变为一个原子操作。

private static Semaphore muntex = new Semaphore(1);
@Override
public void run() {try {muntex.acquire();semaphores[this.philosopherNum].acquire();  //获取锁Thread.sleep((long) (1000));   //拿起筷子的时间,会发生死锁//acquire(): 获取一个许可。如果信号量的许可已经被其他线程占用,那么当前线程会阻塞,直到有许可可用。semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].acquire();System.out.println(this.getName() + "获取到了筷子" + String.valueOf(this.philosopherNum) +"和" + String.valueOf(this.getRightSemaphoreIndex(this.philosopherNum)) + "开始吃饭了");} catch (Exception e) {e.printStackTrace();} finally {//释放一个许可,意味着当前线程已不再占用资源,其他线程可以继续使用该资源。semaphores[(this.philosopherNum)].release();semaphores[this.getRightSemaphoreIndex(this.philosopherNum)].release();muntex.release();}
}

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

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

相关文章

TwinCL: A Twin Graph Contrastive Learning Model for Collaborative Filtering

TwinCL: A Twin Graph Contrastive Learning Model for Collaborative Filtering 摘要 在推荐和协同过滤领域&#xff0c;图对比学习&#xff08;Graph Contrasive Learning&#xff0c;GCL&#xff09;已经成为一种有影响的方法。然而&#xff0c;对比学习有效性的原因还没有…

虚拟现实辅助工程技术如何加速汽车设计与制造

汽车行业正面临着以超常速度进行创新的压力&#xff0c;以满足新出现的环境、技术和社会需求。这就要求产品开发具有极高的效率和准确性。传统的汽车产品开发周期通常依赖于大量的物理原型和实际测试。这些设计周期冗长、成本高昂、资源密集&#xff0c;当需要更改设计时&#…

基于卷积神经网络的农作物病虫害识别系统(pytorch框架,python源码)

更多图像分类、图像识别、目标检测等项目可从主页查看 功能演示&#xff1a; 基于卷积神经网络的农作物病虫害检测&#xff08;pytorch框架&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积神经网络的农作物病虫害识别系统是在pytorch框架下实现的…

现代配电系统中的预付费电能计量装置有哪些功能?

随着社会的快速发展和用电需求的不断增长&#xff0c;传统的后付费电能计量方式逐渐暴露出诸如欠费问题、计费不准确、管理复杂等缺点&#xff0c;无法适应日益复杂的电力供应和消费需求。预付费电能计量装置作为一种新型的电能管理方式&#xff0c;因其具备便捷、智能等特点&a…

优化文本嵌入,大幅提升RAG检索速度

大家好&#xff0c;文本嵌入技术能够将文字信息转换成高维向量表示的数字&#xff0c;提供了一种理解和处理文本数据的新方式&#xff0c;帮助我们更好地理解和处理文本数据。这些向量能够捕捉文本的深层特征&#xff0c;进而支持多种应用&#xff0c;比如理解语义、进行文本分…

【通信领域术语】MNO 和 MVNO 的简介

定义与关系 MNO 和 MVNO 是两种不同类型的移动运营商。 MNO(Mobile Network Operator,移动网络运营商)指利用物理网络基础设施提供移动服务的一种移动服务提供商。 MVNO(Mobile Virtual Network Operator,虚拟移动网络运营商)不拥有网络基础设施。 两者最大的区别在于,…

868历年真题算法设计题+程序设计题

11.52013年真题*4 一天四道太顶了&#xff0c;11.6-11.15先且两天四道题&#xff0c;先把数学二轮三轮结束&#xff01; 如果程序设计题写不了 核心算法 &#xff0c;但是把思路写上去&#xff0c;只将核心函数空出来也能拿些分&#xff01;&#xff01;DFS大概率不会和stack同…

仿制药一致性评价数据库之药品一致性评价查询

在《我不是药神》电影中&#xff0c;白血病特效药“格列宁”原研药与印度仿制药价格相差近10倍&#xff0c;在仿制药生物等效达到99%以上情况下&#xff0c;你会如何抉择&#xff1f;即便在如今的美国&#xff0c;仿制药也占据了90%以上的用药市场。 正如《仿制药的真相》书中…

【JS学习】08. web API-事件进阶

Web APIs - 第3天 进一步学习 事件进阶&#xff0c;实现更多交互的网页特效&#xff0c;结合事件流的特征优化事件执行的效率 掌握阻止事件冒泡的方法理解事件委托的实现原理 事件流 事件流是对事件执行过程的描述&#xff0c;了解事件的执行过程有助于加深对事件的理解&…

Spring Validation数据校检

文章目录 Spring Validation1 关于Spring Validation2 使用流程3 快速入门4 运行异常处理4.1 说明4.2 处理异常4.3 明确提示消息 5 常用注解5.1 NotNull注解5.2 NotEmpty 注解5.3 NotBlank 注解5.4 Size 注解5.5 Range 注解 6 非POJO参数校验6.1 使用流程6.2 使用示例 Spring V…

Node.js 全栈开发进阶篇

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;node.js篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来node.js篇专栏内容:node.js- 全栈开发进阶篇 前言 大家好&#xff0c;我是青山。在上一篇文章中&#xff0c;…

实战| 使用深度学习分割和计算水体和农田面积【Pytorch附源码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

虚拟机 Ubuntu 扩容

文章目录 一、Vmware 重新分配 Ubuntu 空间二、Ubuntu 扩容分区 一、Vmware 重新分配 Ubuntu 空间 先打开 Vmware &#xff0c;选择要重新分配空间的虚拟机 点击 编辑虚拟机设置 &#xff0c;再点击 硬盘 &#xff0c;再点击 扩展 选择预计扩展的空间&#xff0c;然后点击 扩展…

Mybatis的高级用法

MybatisPlus 实体类注释字段 TableName&#xff08;“数据库表名”&#xff09; TableId&#xff08;“主键名”&#xff09; TableField&#xff08;“字段名”&#xff09; BaseMapper接口对象方法 普通查询 1、主键 T selectById(Serializable id) 使用场景为通过主…

excel表格加锁忘密码怎么解决?

百度好多方法都无效&#xff0c;下面方法可行&#xff1a; 点击sheet单元格名称&#xff0c;鼠标右边出现弹框选择“查看代码”&#xff1a; 出现的框中输入以下代码: Sub demo()// 锁定当前工作表&#xff0c;允许筛选操作ActiveSheet.Protect DrawingObjects:True, CONTENT…

Vue中ref、reactive、toRef、toRefs的区别

一、ref、reactive setup 函数中默认定义的变量并不是响应式的&#xff08;即数据变了以后页面不会跟着变&#xff09;&#xff0c;如果想让变量变为响应式的变量&#xff0c;需要使用 ref 和 reactive 函数修饰变量。 ref 函数可以把基本类型变量变为响应式引用reactive 函数…

PDF全能免费转换 3.18 | 免费PDF工具集,多种转换和美化功能

PDF全能免费转换是一款主打免费好用的PDF工具集&#xff0c;功能丰富且实用。主要功能包括&#xff1a;PDF转Word/PPT/Excel/TXT/图片&#xff0c;PDF压缩和合并&#xff0c;多图合并成长图或PDF&#xff0c;身份证扫描、文件扫描、证件扫描&#xff0c;证件照换底色&#xff0…

DICOM标准:DICOM标准中的公用模块、核心模块详解(一)——病人、研究、序列、参考帧和设备模块属性详解

目录 概述 1 公用病人IE模块 1.1 病人模块 2 公用的研究IE模块 2.1 常规研究模块 2.2 病人研究模块 3 公用序列IE模块 3.1 常规序列模块 3.1.1 常规序列属性描述 4 公用参考帧信息实体模块 4.1 参考帧模块 4.1.1 参考帧属性描述 5 公用设备IE模块 5.1 常规设备模…

Webpack 配置module.css报错Uncaught TypeError: Cannot read properties of undefined

我的项目结构如下: 入口文件是index.jsx&#xff0c;组件Button.jsx使用了样式button.module.css .btn {background-color: #4CAF50;border: none;color: white; padding: 15px 32px;text-align: center;text-decoration: none;display: inline-block;font-size: 16px;margin:…

PyCharm中pylint安装与使用

目录 1. 安装插件2. pycharm中使用该功能3. 命令行使用 1. 安装插件 然后重启 2. pycharm中使用该功能 3. 命令行使用 前提是先 pip install pylint pylint demo01.py下面红框内容的意思是&#xff0c;得到10分/ 满分10分&#xff0c;上次运行获得8.33分&#xff0c;经调整…