Java面试题:什么是死锁?如何手写一个死锁(Dead Lock)

2024-06-15 07:38

本文主要是介绍Java面试题:什么是死锁?如何手写一个死锁(Dead Lock),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要想实现一个死锁,首先要明白什么是死锁,我们看一下死锁的定义:

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。--百度

用通俗的话来说就是张三跟李四下饭馆吃饺子,张三拿着醋,李四拿着蒜瓣,张三说李四你给我吃点蒜,李四说,那不行,你得先给我醋,要不然我不给你,张三也不乐意了,说你必须先给我蒜瓣,我再给你醋,这种现象就是死锁。(Dead Lock)

我们知道使用Synchronize锁两个对象很容易发生这种事,话不多说,直接上代码:

package Thread;public class DumplingDeadLockDemo implements Runnable{static Object garlic = new Object();static Object vinegar = new Object();int flag = 0;@Overridepublic void run() {if (flag == 0) {synchronized (vinegar) {try {Thread.sleep(500);} catch (InterruptedException e) {return;}System.out.println("我张三正在吃醋,李四你给我点蒜瓣");synchronized (garlic) {System.out.println("我张三终于吃上蒜了,hiahia~");}}}if (flag == 1) {synchronized (garlic) {try {Thread.sleep(500);} catch (InterruptedException e) {}System.out.println("俺李四正在吃蒜,张三你给我点醋");synchronized (vinegar) {System.out.println("我李四终于吃上醋了,hiahia~");}}}}public static void main(String[] args) {DumplingDeadLockDemo ZhangSan = new DumplingDeadLockDemo();DumplingDeadLockDemo LiSi = new DumplingDeadLockDemo();ZhangSan.flag = 0;LiSi.flag = 1;Thread t1 = new Thread(ZhangSan);Thread t2 = new Thread(LiSi);t1.start();t2.start();}
}

需要注意,新手容易犯的错是把两个synchronized分开写了,那么就永远都不会成了死锁,死锁发生的四个必要条件是:

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

 

拿我这个例子来说,想要死锁,必须满足:

互斥性:张三和李四必须吃了醋再吃蒜或者吃了蒜再吃醋,两个事件不可同时发生,否则不满足互斥性自然也不会构成死锁。

请求和保持条件:至少保证张三拿着醋,李四拿着蒜瓣,但是张三还非得要吃蒜,李四还非得吃醋,否则缺少一个条件都不构成死锁。

不剥夺条件:张三拿着醋,没完成吃蒜这个事件,李四绝对不能过来抢,否则不满足不剥夺条件。

环路等待条件:

一定要构成这种环形等待。

 

这篇关于Java面试题:什么是死锁?如何手写一个死锁(Dead Lock)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062830

相关文章

Spring Boot整合Redis注解实现增删改查功能(Redis注解使用)

《SpringBoot整合Redis注解实现增删改查功能(Redis注解使用)》文章介绍了如何使用SpringBoot整合Redis注解实现增删改查功能,包括配置、实体类、Repository、Se... 目录配置Redis连接定义实体类创建Repository接口增删改查操作示例插入数据查询数据删除数据更

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题

Java使用Swing生成一个最大公约数计算器

《Java使用Swing生成一个最大公约数计算器》这篇文章主要为大家详细介绍了Java使用Swing生成一个最大公约数计算器的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下... 目录第一步:利用欧几里得算法计算最大公约数欧几里得算法的证明情形 1:b=0情形 2:b>0完成相关代码第二步:加

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

Java Map排序如何按照值按照键排序

《JavaMap排序如何按照值按照键排序》该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实... 目录一、先理清 3 种 Map 的默认排序行为二、按「键」排序的实现方式1. 方式 1:用 TreeM

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node