关于对死锁的理解

news2025/2/24 23:30:25

文章目录

    • 什么是死锁?
    • 举例理解死锁
    • 如何解决死锁
    • 锁池与等待池的理解
      • 什么是锁池与等待池
      • 锁池与等待池的区别
    • 两个线程交替执行

什么是死锁?

所谓死锁,是指互斥锁标记使用不当造成多个线程,相互持有对方想要申请的资源,不释放的情况下又去主动申请对方已经持有的资源从而双双进入对方持有资源的锁池当中 产生永久的阻塞 - 死锁 DeadLock。

举例理解死锁

中美科学家联合国饿死事件

中国科学家拿着刀叉想吃面条

美国科学家拿着筷子想吃面条

泉城路奔宝事件
奔驰占领泉城路东侧 想要开往泉城路西侧

宝马占领泉城路西侧 想要开往泉城路东侧

在这里插入图片描述

下面以泉城路奔宝事件举例说明

public class TestDeadLock{
    public static void main(String[] args){
        QCRoad r = new QCRoad();
        QCRoad.Benz s900 = r.new Benz();
        QCRoad.Bmw x9 = r.new Bmw();
        s900.start();
        x9.start();
    }
}
class QCRoad{//餐厅
    Object east = new Object();//路东资源   刀叉
    Object west = new Object();//路西资源    筷子

    class Benz extends Thread{//中国人
        @Override
        public void run(){
            System.out.println("勋总驾驶奔驰驶出家门 去上课~");
            synchronized(east){
                System.out.println("勋总和他的奔驰已经占领了泉城路东侧~");
                synchronized(west){
                    System.out.println("勋总和他的奔驰又占领了泉城路西侧~");
                }
            }

            System.out.println("勋总顺利的通过了泉城路");
        }
    }
    class Bmw extends Thread{//美国人
        @Override
        public void run(){
            System.out.println("良总驾驶宝马驶出家门 去上课~");
            synchronized(west){
                System.out.println("良总和他的宝马已经占领了泉城路西侧~");
                synchronized(east){
                    System.out.println("良总和他的宝马又占领了泉城路东侧~");
                    east.notify();
                }
            }
            System.out.println("良总顺利的通过了泉城路");
        }
    }
}

奔驰占领泉城路东侧宝马占领泉城路西侧无法通行,从而产生死锁
在这里插入图片描述

多运行几次发现通过了

在这里插入图片描述

怎么回事?

宝马去晚了 没堵住~

为了演示死锁让奔驰占领路懂后不要往西开,宝马占领路西后不要往东开 睡一会~

public class TestDeadLock{
    public static void main(String[] args){
        QCRoad r = new QCRoad();
        QCRoad.Benz s900 = r.new Benz();
        QCRoad.Bmw x9 = r.new Bmw();
        s900.start();
        x9.start();
    }
}
class QCRoad{//餐厅
    Object east = new Object();//路东资源   刀叉
    Object west = new Object();//路西资源    筷子

    class Benz extends Thread{//中国人
        @Override
        public void run(){
            System.out.println("勋总驾驶奔驰驶出家门 去上课~");
            synchronized(east){
                System.out.println("勋总和他的奔驰已经占领了泉城路东侧~");
                try{sleep(100);}catch(Exception e){e.printStackTrace();}
                synchronized(west){
                    System.out.println("勋总和他的奔驰又占领了泉城路西侧~");
                }
            }
            System.out.println("勋总顺利的通过了泉城路");
        }
    }
    class Bmw extends Thread{//美国人
        @Override
        public void run(){
            System.out.println("良总驾驶宝马驶出家门 去上课~");
            synchronized(west){
                System.out.println("良总和他的宝马已经占领了泉城路西侧~");
                try{sleep(100);}catch(Exception e){e.printStackTrace();}
                synchronized(east){
                    System.out.println("良总和他的宝马又占领了泉城路东侧~");
                }
            }
            System.out.println("良总顺利的通过了泉城路");
        }
    }

}

如何解决死锁

一块空间

对象的等待池
在这里插入图片描述

三个方法

  • wait() : 让当前线程放弃已经持有的锁标记 并且进入调用方法的那个对象的等待池当中

  • notify() : 从调用方法的那个对象的等待池当中随机的唤醒一个线程

  • notifyAll() : 从调用方法的那个对象的等待池当中唤醒所有阻塞的线程

这三个方法都是Object类的方法 所以 任何一个对象 都可以使用
因为任何一个对象都有等待池

这三个方法都必须在已经持有锁标记的前提下才能使用 否则 不但是调用失败
还会触发运行时异常~

如何使用

使用wait()让奔驰去等待池阻塞 宝马通过后再notify()让奔驰出来

public class TestDeadLock{
    public static void main(String[] args){
        QCRoad r = new QCRoad();
        QCRoad.Benz s900 = r.new Benz();
        QCRoad.Bmw x9 = r.new Bmw();
        s900.start();
        x9.start();
    }
}
class QCRoad{//餐厅
    Object east = new Object();//路东资源   刀叉
    Object west = new Object();//路西资源    筷子

    class Benz extends Thread{//中国人
        @Override
        public void run(){
            System.out.println("勋总驾驶奔驰驶出家门 去上课~");
            synchronized(east){
                System.out.println("勋总和他的奔驰已经占领了泉城路东侧~");
                try{sleep(100);}catch(Exception e){e.printStackTrace();}
                try{east.wait();}catch(Exception e){e.printStackTrace();}
                synchronized(west){
                    System.out.println("勋总和他的奔驰又占领了泉城路西侧~");
                }
            }

            System.out.println("勋总顺利的通过了泉城路");
        }
    }
    class Bmw extends Thread{//美国人
        @Override
        public void run(){
            System.out.println("良总驾驶宝马驶出家门 去上课~");
            synchronized(west){
                System.out.println("良总和他的宝马已经占领了泉城路西侧~");
                try{sleep(100);}catch(Exception e){e.printStackTrace();}
                synchronized(east){
                    System.out.println("良总和他的宝马又占领了泉城路东侧~");
                    east.notify();
                }
            }
            System.out.println("良总顺利的通过了泉城路");
        }
    }
}

锁池与等待池的理解

什么是锁池与等待池

锁池: 假设线程A已经拥有了某个对象(不是类)的锁,而其他线程B,C想要调用这个对象的某个synchronized方法(或者块),由于B,C线程在进入对象的synchronized方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正被线程A所占用,此时B,C线程会被阻塞,进入一个地方去等待锁的释放,这个地方就是该对象的锁池。
等待池: 假设线程A调用了某个对象的wait方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁。

锁池与等待池的区别

锁池和等待池都是Java当中每个对象都有一份的 用来放置线程的空间

进入的时候是否需要释放资源
锁池: 不需要释放资源就能直接进入 (所以才会形成死锁)
等待池: 必须要先释放资源 才能进入

离开的时候是否需要调用方法
锁池: 不需要 一旦锁标记归还再度可用 锁池就可以解除
等待池: 必须要另外的线程主动唤醒 notify() / notifyAll()

离开之后去到什么状态
离开锁池: 前往就绪状态
离开等待池: 前往锁池! [等着唤醒我的线程释放锁标记]

两个线程交替执行

比如 顺丰 有些东西是不能上飞机的 只能陆运
顺丰就要安排大货车配合两个司机

public class BigOne{
    public static void main(String[] args){
        RightThread rt = new RightThread();
        LeftThread lt = new LeftThread(rt);

        lt.start();
        //rt.start();
    }
}
class X{
    static Object obj = new Object();
}
class LeftThread extends Thread{
    RightThread rt;
    public LeftThread(RightThread rt){
        this.rt = rt;
    }
    @Override
    public void run(){
        synchronized(X.obj){
            rt.start();
            for(int i = 0;i<6666;i++){
                System.out.println("左脚");
                try{X.obj.wait();}catch(Exception e){e.printStackTrace();}
                X.obj.notify();
            }
        }
    }
}
class RightThread extends Thread{
    @Override
    public void run(){
        synchronized(X.obj){
            for(int i = 0;i<6666;i++){
                System.out.println("            右脚");
                X.obj.notify();
                try{X.obj.wait();}catch(Exception e){e.printStackTrace();}
            }
        }
    }
}

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

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

相关文章

HummerRisk V0.7.0:支持京东云、webhook、PDF下载等

HummerRisk V0.7.0发布&#xff1a;新增京东云支持&#xff0c;系统增加webhook支持&#xff0c;灵活扩展&#xff0c;新增多种页面的PDF下载&#xff0c;新增主机的批量导入和Windows类型主机的检测支持。 感谢社区中小伙伴们的反馈&#xff0c;你们的认可是我们前进的动力。…

四旋翼无人机学习第16节--labview开发allegro的PAD与封装查询工具

文章目录1 前言2 使用展示(有labview软件)2.1 使用界面展示2.2 配置文件展示2.3 封装检索2.4 pad检索2.5 软件退出3 使用展示(无labview软件)4 源文件下载方式1 前言 在学习allegro过程中&#xff0c;设计封装需要先设计组成封装的PAD&#xff0c;也就是使用Padstack Editor工…

Linux学习-93-SELinux安全上下文操作

18.6 SELinux安全上下文查看方法 SELinux 管理过程中&#xff0c;进程是否可以正确地访问文件资源&#xff0c;取决于它们的安全上下文。进程和文件都有自己的安全上下文&#xff0c;SELinux 会为进程和文件添加安全信息标签&#xff0c;比如 SELinux 用户、角色、类型、类别等…

Android设计模式详解之原型模式

前言 原型模式是一个创建型设计模式。 定义&#xff1a;用原型实例指定创建对象的种类&#xff0c;并通过复制这些原型创建新的对象。 使用场景&#xff1a; 类初始化需要消耗非常多的资源&#xff0c;这个资源包括数据、硬件资源&#xff0c;通过原型复制避免这些消耗&…

音质更出色的骨传导耳机,设计也很时尚,南卡Runner CC3上手

这两年我几乎每天都会用耳机&#xff0c;现在耳机的种类也不少&#xff0c;如果是户外健身的话&#xff0c;我觉得骨传导耳机比挂脖式的耳机更好用&#xff0c;这种耳机因为不入耳的使用方式&#xff0c;在我们听音乐的同时&#xff0c;还可以更清晰地感知周围的情况&#xff0…

【Django项目开发】自动生成接口文档(二)

文章目录一、安装第三方库drf-yasg2二、注册到子应用INSTALLED_APPS三、配置路由1、注意四、接口文档中展示详细的文档说明视图类中接口的标准注释五、视图类中自己定义的方法实现接口文档注释1、注意一、安装第三方库drf-yasg2 pip install drf-yasg2二、注册到子应用INSTALL…

新技术不断发展,一个全新的互联网行业的新风口已然来临

拥抱实体经济&#xff0c;绝对是当下互联网玩家们的首要选择。无论是头部的互联网企业来讲&#xff0c;还是新生的互联网玩家而言&#xff0c;它们都不约而同地将关注的焦点聚焦在了这样一个方向上。   透过这一点&#xff0c;我们可以非常明显地感受到&#xff0c;一个全新的…

网络技术展开型介绍(超详细)二

♥️作者&#xff1a;小刘在这里 ♥️每天分享云计算网络运维课堂笔记&#xff0c;疫情之下&#xff0c;你我素未谋面&#xff0c;但你一定要平平安安&#xff0c;一 起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的&#xff0c;绽放&#xff0c;…

MyBatis—MyBatis参数详解

文章目录MyBatis参数详解1、 parameterType2、resultType3、 resultMap结果类型MyBatis获取参数值的两种方式1.配置sql输出日志2.看#{}和${}的输出现象3.#{}的预编译4.sql注入5.什么时候使用${}6.如何选择使用 #{} 和 ${}7.为什么#{}可以预防sql注入—————————————…

Shuffle的作用以及MapReduce的Shuffle过程

Shuffle的设计 为什么需要Shuffle&#xff1f; Shuffle的本质是基于磁盘划分来解决分布式大数据量的全局分组、全局排序、重新分区【增大】 等问题 因为单台机器的资源处理不了分布式大数据量全局分区/排序/分组 所以需要通过Shuffle对每一台机器的数据构建一个Task来做分区的…

通关剑指 Offer——剑指 Offer II 055. 二叉搜索树迭代器

1.题目描述 剑指 Offer II 055. 二叉搜索树迭代器 实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会…

20221221英语学习

今日新词 define v.下定义&#xff1b;确切说明&#xff08;或解释&#xff09;&#xff1b;树立&#xff0c;表明 chemistry n.化学, 物质的化学组成&#xff08;或性质&#xff09; fly v.飞, 飞翔, 航行, &#xff08;乘航空器或航天器&#xff09;航行 forfeit v.&…

港华燃气上线WeOps推动运维效能提升,托举业务智慧运行!

“嘉为蓝鲸WeOps一体化运维平台有效提升了运维工作效率&#xff0c;满足系统安全要求&#xff0c;尤其是补丁安装、巡检自动化、监控告警等功能&#xff0c;为我们节省了运维人力成本和时间成本。” ——来自港华燃气 港华集团介绍&#xff1a; 港华集团为香港中华煤气在内地…

m在LTE-A系统载波聚合下的资源分配算法的matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 载波聚合即CA&#xff0c;是LTE-A中的关键技术。是为满足用户峰值速率和系统容量提升的要求&#xff0c;增加系统传输带宽的技术&#xff0c;通过CA技术&#xff0c;用户最高上网速率可提升到300…

IPv4 和 IPv6 报文格式详解

文章目录1 概述2 报文格式2.1 IPv42.2 IPv62.3 两者区别3 网工软考真题1 概述 2 报文格式 2.1 IPv4 中文名英文名长度 bit&#xff08;位&#xff09;解释版本Version4IP协议版本号&#xff0c;固定为 4首部长度Header Length4数据报首部的总长度。 以 4 Byte&#xff08;字节…

【Java基础知识复盘】Java概述篇

本人知识复盘系列的博客并非全部原创&#xff0c;大部分摘自网络&#xff0c;只是为了记录在自己的博客方便查阅&#xff0c;往后也会陆续在本篇博客更新本人查阅到的新的知识点&#xff0c;望悉知&#xff01; Java概述 何为编程 编程就是让计算机为解决某个问题而使用某种程…

100多条2023年元宇宙统计数据!Hubbleverse替你整理好了!

欢迎来到Hubbleverse &#x1f30d; 关注我们 关注宇宙新鲜事 &#x1f4cc; 预计阅读时长&#xff1a;9分钟 本文仅代表作者个人观点&#xff0c;不代表平台意见&#xff0c;不构成投资建议。 元宇宙最近被评为最热门的新兴技术趋势之一。在过去的几年里&#xff0c;元宇宙…

SpringBoot整合Mybatis之Mapper接口和映射文件

一、什么是MyBatis MyBatis中文网https://mybatis.net.cn/ MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型…

消息中间件执行原理

1 关于消息中间件 1.1 什么是消息中间件&#xff1f; 消息中间件是指在分布式系统中完成消息的发送和接收的基础软件。 消息中间件也可以称消息队列&#xff08;Message Queue / MQ&#xff09;&#xff0c;用高效可靠的消息传递机制进行与平台无关的数据交流&#xff0c;并基…

区块链技术应用展望

区块链作为一个"去中心化"的分布式账本数据库&#xff0c;能够让数据的产生、运行和应用更加公开与透明。区块链被认为是互联网之后又一大创新之举&#xff0c;是第二个互联网时代——价值互联网时代的来临&#xff0c;区块链将从基础设施层面为各行各业带来巨大的变…