返回顶部
首页 > 资讯 > 后端开发 > Python >Java多线程之哲学家就餐问题详解
  • 762
分享到

Java多线程之哲学家就餐问题详解

2024-04-02 19:04:59 762人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录一、题目二、题目解析三、代码实现四、运行效果截图五、结语一、题目 教材提供一个哲学家就餐问题的解决方案的框架。本问题要求通过pthreads 互斥锁来实现这个解决方案。 哲学家

一、题目

教材提供一个哲学家就餐问题的解决方案的框架。本问题要求通过pthreads 互斥来实现这个解决方案。
哲学家 首先创建 5 个哲学家,每个用数字 0~4 来标识。每个哲学家作为一个单独的 线程运行。 可使用 Pthreads 创建线程。哲学家在思考和吃饭之间交替。为了模拟这两种活动,请让线程休眠 1 到 3 秒钟。当哲学家想要吃饭时,他调用函数:
pickup_forks(int philosopher _number) 其中,philosopher _number
为想吃饭哲学家的数字。当哲学家吃完后,他调用函数:


return _forks(int philosopher _number)

Pthreads 条件变量 Pthreads 条件变量使用数据类型 pthread_cond_t,采用函数 pthread cond
init()初始化。以下代码创建并初始化条件变量及其关联的互斥锁:


pthread _mutex_ t mutex;
pthread_ cond_ t cond _var;
pthread _mutex_ init(&mutex,NULL);
pthread _cond_ init(&cond _var,NULL);

函数 pthread_cond_wait()用于等待条件变量。下面的代码采用 Pthreads条件变量,说明线程如何等待条件 a==b 变为
true。


pthread _mutex_ lock(&mutex);
while (a != b)
pthread_cond _wait(&mutex, &cond var);
pthread _mutex_ unlock(&mutex);

与条件变量关联的互斥锁在调用pthread_cond_wait()函数之前,应加锁,因为保护条件语句中的数据,避免竞争条件。一旦获得锁,线程可以检查条件。如果条件不成立,然后线程调用 pthread_cond_wait(),传递互斥锁和条件变量作为参数。调用pthread_cond_wait()释放互斥锁,从而允许另一个线程访问共享变量,也可更新其值,以便条件语句的计算结果为真。(为了防止程序错误,重要的是将条件语句放在循环中,以便在被唤醒后重新检查条件。)修改共享数据的线程可以调用 pthread_cond_signal()函数,从而唤醒一个等待条件变量的线程。这个代码如下:


pthread_ mutex_ lock(&mutex);
a = b;
pthread_ cond_ signal(&cond var);
pthread _mutex_ unlock(&mutex);

需要注意的是,调用pthread_cond_signal()不会释放互斥锁。随后调用pthread_mutex_unlock()释放互斥锁。一旦互斥锁被释放,唤醒线程成为互斥锁的所有者,并将控制权返回到对pthread cond wait()的调用。

二、题目解析

题目是书上的哲学家就餐问题,要求用互斥锁解决。
这题的关键在于筷子这个资源的合理使用,书上给出了三种不同的解决思路:

在这里插入图片描述

其实三种方法的核心就是为了解决死锁问题。

什么是死锁呢?

用专业点的话说就是:一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象

说白了,就是你拿了我想要拿的资源,我拿了你想要拿的资源,而双方各执一词,导致一直无法解决问题

那我的思路就是:

双方各退一步,当发现我想要的资源不够我完成我所需的事情时,那就把之前拿到的资源放回。这样就不会导致双方互相等待导致死锁的情况。

当然思路不止一种,在极客时间的Java并发编程实战中有讲到死锁发生的条件:

只有以下这四个条件都发生时才会出现死锁:

互斥,共享资源 X 和 Y 只能被一个线程占用;占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;不可抢占,其他线程不能强行抢占线程 T1 占有的资源;循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。

如何解决死锁呢?打破任意一个条件即可。

其中,互斥这个条件我们没有办法破坏,因为我们用锁为的就是互斥。不过其他三个条件都是有办法破坏掉的,到底如何做呢?

对于“占用且等待”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。对于“不可抢占”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。对于“循环等待”这个条件,可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环了。

好了,回到正题上来,既然我们的思路就是拿不到资源就选择退让,我们可以借用Java里的ReentrantLock类中trylock()方法实现,该方法的作用就是尝试锁住该资源。和lock()方法不同的是,如果该资源已经上锁,那么线程不会阻塞,而是返回flase,表示无法上锁,当然还可以加入参数让它再尝试几秒,比如:


lock.tryLock(1, TimeUnit.SECONDS));

而具体用法就是


if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        ...
    } finally {
        lock.unlock();
    }
}

三、代码实现


package com.dreamchaser.concurrent;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Proj3_02 {
    static final Lock[] locks=new Lock[5];
    static {
        for (int i=0;i<locks.length;i++){
            locks[i]=new ReentrantLock();
        }
    }

    public static void main(String[] args) {
        Philosopher philosopher0=new Philosopher("张三",1000,0);
        Philosopher philosopher1=new Philosopher("李四",800,1);
        Philosopher philosopher2=new Philosopher("王五",400,2);
        Philosopher philosopher3=new Philosopher("jhl",2000,3);
        Philosopher philosopher4=new Philosopher("ghlcl",2000,4);
        philosopher0.start();
        philosopher1.start();
        philosopher2.start();
        philosopher3.start();
        philosopher4.start();
        //死循环,防止主线程退出导致进程关闭
        while (true){}
    }

    static class Philosopher extends Thread{
        private String name;
        private long time;
        private int num;

        public Philosopher(String name, long time, int num) {
            this.name = name;
            this.time = time;
            this.num = num;
        }

        @Override
        public void run() {
            while (true){
                System.out.println(num+"号哲学家"+name+"正在思考...");
                //模拟思考的过程
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(num+"号哲学家"+name+"饿了,想来吃饭...");
                if (locks[num].tryLock()){
                    try {
                        System.out.println(num+"号哲学家"+name+"拿到了左边的筷子!");
                        if (locks[(num+1)%5].tryLock()){
                            try {
                                System.out.println(num+"号哲学家"+name+"拿到了右边的筷子!");
                                System.out.println(num+"号哲学家"+name+"开始吃饭!");
                                //模拟哲学家吃饭的过程
                                Thread.sleep(time);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                System.out.println(num+"号哲学家"+name+"放下了右边的筷子!");
                                locks[(num+1)%5].unlock();
                            }
                        }else {
                            System.out.println(num+"号哲学家"+name+"没拿到了右边的筷子!被迫思考...");
                        }
                    }finally {
                        System.out.println(num+"号哲学家"+name+"放下了左边的筷子!");
                        locks[num].unlock();
                    }
                }else {
                    System.out.println(num+"号哲学家"+name+"没拿到了左边的筷子!被迫思考...");
                }
                System.out.println(num+"号哲学家"+name+"思考ing...");
                //模拟思考过程
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

四、运行效果截图

在这里插入图片描述

在这里插入图片描述

五、结语

以上是我的实现思路。希望我的思路能个各位有所帮助,当然,如果有什么意见或者建议的,欢迎在评论区评论。

到此这篇关于Java多线程之哲学家就餐问题详解的文章就介绍到这了,更多相关Java哲学家就餐详解内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java多线程之哲学家就餐问题详解

本文链接: https://lsjlt.com/news/124536.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java多线程之哲学家就餐问题详解
    目录一、题目二、题目解析三、代码实现四、运行效果截图五、结语一、题目 教材提供一个哲学家就餐问题的解决方案的框架。本问题要求通过pthreads 互斥锁来实现这个解决方案。 哲学家...
    99+
    2024-04-02
  • Java线程同步问题--哲学家就餐
    目录1.场景2.解决方案方法一:限制吃饭的哲学家人数方法二:找到一个左撇子哲学家 1.场景 有五位沉默的哲学家围坐在一张圆桌旁,他们一生都在吃东西和思考。 有五只筷子供他们使用,哲学...
    99+
    2024-04-02
  • Java多线程之线程安全问题详解
    目录1. 什么是线程安全和线程不安全?2. 自增运算为什么不是线程安全的?3. 临界区资源和竞态条件总结:面试题: 什么是线程安全和线程不安全?自增运算是不是线程安全的?如何保证多线...
    99+
    2024-04-02
  • Java多线程之线程安全问题详情
    目录1.线程安全概述1.1什么是线程安全问题1.2一个存在线程安全问题的程序2.线程加锁与线程不安全的原因2.1案例分析2.2线程加锁2.2.1什么是加锁2.2.2如何加锁2.2.3...
    99+
    2024-04-02
  • Java多线程之线程安全问题
    文章目录 一. 线程安全概述1. 什么是线程安全问题2. 一个存在线程安全问题的程序 二. 线程不安全的原因和线程加锁1. 案例分析2. 线程加锁2.1 理解加锁2.2 synchroni...
    99+
    2023-09-21
    java 线程安全 多线程 synchronized jvm
  • Java多线程之线程安全问题怎么解决
    本篇内容主要讲解“Java多线程之线程安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程之线程安全问题怎么解决”吧!1.线程安全概述1.1什么是线程安全问题首先我们需要...
    99+
    2023-06-30
  • Java多线程之线程状态详解
    目录 线程状态停止线程线程休眠模拟网络延迟(放大问题的发生性)模拟计时线程礼让插队(线程强制执行)线程状态观测线程优先级守护线程总结 线程状态 五个状态:新生、就...
    99+
    2024-04-02
  • Java多线程之Interrupt中断线程详解
    目录一、测试代码二、测试三、执行过程描述四、输出日志五、结论六、主要方法释义七、DEMO八、拓展程序九、实战一、测试代码 https://gitee.com/zture/sprin...
    99+
    2024-04-02
  • Java多线程之死锁详解
    目录1、死锁2、死锁经典问题——哲学家就餐问题 总结1、死锁 出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁;线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程...
    99+
    2024-04-02
  • Java多线程解决龟兔赛跑问题详解
    目录多线程4(龟兔赛跑-休眠线程)1.题目2.解题思路3.代码详解多线程4(龟兔赛跑-休眠线程) 1.题目 在龟兔赛跑中,领先的兔子因为通宵写博客,中途太累睡着了,跑输了乌龟。这个故...
    99+
    2024-04-02
  • Java多线程死锁问题详解(wait和notify)
    目录一. synchronnized 的特性1. 互斥性2. 可重入性二. 死锁问题1. 什么是死锁2. 死锁的四个必要条件3. 常见的死锁场景及解决3.1 不可重入造成的死锁3.2...
    99+
    2023-01-05
    Java多线程死锁 java死锁的原因及解决方法 java多线程死锁问题
  • Java多线程之死锁问题,wait和notify
    文章目录 一. synchronnized 的特性1. 互斥性2. 可重入性 二. 死锁问题1. 什么是死锁2. 死锁的四个必要条件3. 常见的死锁场景及解决3.1 不可重入造成的死锁3....
    99+
    2023-09-13
    java 死锁 wait notify synchronized
  • Java多线程之线程池七个参数详解
    目录corePoolSize:核心线程数maximumPoolSize:最大线程数keepAliveTime:空闲线程存活时间unit:时间单位workQueue:工作队列threa...
    99+
    2024-04-02
  • Java多线程之线程状态的迁移详解
    目录一、六种状态二、状态迁移图三、线程状态模拟总结一、六种状态 java.lang.Thread 的状态分为以下 6 种,它们以枚举的形式,封装在了Thread类内部: NEW:表...
    99+
    2024-04-02
  • Java 线程池常见问题详解
    线程池是一个预定义线程集合,可按需提供给应用程序使用。它通过管理线程的创建和销毁,简化了线程处理,提高了应用程序的性能和可伸缩性。 为什么使用线程池? 使用线程池有以下好处: 减少线程创建和销毁的开销,提高性能。 限制并发线程数,防止系...
    99+
    2024-03-13
    线程池
  • Java多线程之同步锁-lock详解
    目录一、题目描述二、解题思路三、代码详解一、题目描述 题目: 同步锁出现的目的就是为了解决多线程安全问题。 同步锁的几种方式 synchronized 1、同步代码块 2、同步方法 ...
    99+
    2024-04-02
  • C++11学习之多线程的支持详解
    目录C++11中的多线程的支持1.C++11中的原子类型1.1 原子类型的接口1.2简单自旋锁的实现2.提高并行程度2.1 memory_order的参数2.2 release-ac...
    99+
    2023-02-06
    C++11多线程支持 C++11多线程
  • Java学习之线程同步与线程间通信详解
    目录线程同步的概念同步代码块同步方法线程组线程组的相关方法线程组对象的基本应用线程间的通信线程通信简单应用线程同步的概念 由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时...
    99+
    2022-12-27
    Java线程同步 Java线程通信 Java线程
  • java多线程死锁问题的详细介绍
    本篇内容主要讲解“java多线程死锁问题的详细介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java多线程死锁问题的详细介绍”吧!一、什么是死锁当两个或两个...
    99+
    2024-04-02
  • Java多线程模拟银行系统存钱问题详解
    目录一、题目描述二、解题思路三、代码详解多学一个知识点一、题目描述 题目:模拟一个简单的银行系统,使用两个不同的线程向同一个账户存钱。 实现:使用特殊域变量volatile实现同步。...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作