【JVM】面试题之死锁及问题是怎么定位
前言
之前面试的时候被问到死锁这块的问题,借着最近学习jvm来总结下死锁相关的知识。如果有地方写的不到位的地方,麻烦读者及时提出,放在评论区,我这边也好及时改正。
回顾
所谓,温故而知新,首先回顾下,我们之前学过的线程的状态以及死锁产生的条件。
线程的状态在Java中线程的状态一共被分成6种:
<ignore_js_op>![]()
初始态(NEW)
创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态。
运行态(RUNNABLE),在Java中,运行态包括 就绪态 和 运行态。
就绪态
该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运 行。 所有就绪态的线程存放在就绪队列中。
运行态
获得CPU执行权,正在执行的线程。
由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一条 运行态的线程。
阻塞态(BLOCKED)
当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。
而在Java中,阻塞态专指请求锁失败时进入的状态。
由一个阻塞队列存放所有阻塞态的线程。
处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执 行。
等待态(WAITING)
当前线程中调用wait、join、park函数时,当前线程就会进入等待态。
也有一个等待队列存放所有等待态的线程。
线程处于等待态表示它需要等待其他线程的指示才能继续运行。
进入等待态的线程会释放CPU执行权,并释放资源(如:锁)
超时等待态(TIMED_WAITING)
当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就 会进入该状态;
它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后需要其 他线程唤醒;
进入该状态后释放CPU执行权 和 占有的资源。
与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁。
终止态(TERMINATED)
线程执行结束后的状态。
死锁产生的条件
互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链死锁问题
构造死锁
编写代码,启动2个线程,Thread1拿到了obj1锁,准备去拿obj2锁时,obj2已经被 Thread2锁定,所以发送了死锁。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public class TestDeadLock { private static Object obj1 = new Object(); private static Object obj2 = new Object(); public static void main(String[] args) { new Thread(new Thread1()).start(); new Thread(new Thread2()).start(); } private static class Thread1 implements Runnable { @Override public void run() { synchronized (obj1) { System.out.println("Thread1 拿到 obj1 的锁"); try { //停顿2秒的意义在于,让thread2线程拿到obj2的锁 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { System.out.println("Thread1 拿到 obj2 的锁"); } } } } private static class Thread2 implements Runnable { @Override public void run() { synchronized (obj2) { System.out.println("Thread2 拿到 obj2 的锁"); try { //停顿2秒的意义在于,让thread1线程拿到obj1的锁 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj1) { System.out.println("Thread2 拿到 obj1 的锁"); } } } }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
[root@localhost test]# javac TestDeadLock.java [root@localhost test]# lltotal 27692drwxr-xr-x. 9 root root 220 Jan 3 23:22 apache-tomcat-7.0.99-rw-r--r--. 1 root root 9587605 Dec 11 21:44 apache-tomcat-7.0.99.tar.gz-rw-------. 1 root root 18737999 Jan 4 16:52 dump.dat-rw-r--r--. 1 root root 433 Jan 3 23:23 Main.class-rw-r--r--. 1 root root 135 Jan 3 23:23 Main.java-rw-r--r--. 1 root root 184 Jan 5 10:08 TestDeadLock$1.class-rw-r--r--. 1 root root 843 Jan 5 10:08 TestDeadLock.class-rw-r--r--. 1 root root 1547 Jan 5 10:02 TestDeadLock.java-rw-r--r--. 1 root root 1066 Jan 5 10:08 TestDeadLock$Thread1.class-rw-r--r--. 1 root root 1066 Jan 5 10:08 TestDeadLock$Thread2.class[root@localhost test]# java TestDeadLockThread1 拿到 obj1 的锁Thread2 拿到 obj2 的锁#这里发生了死锁,程序一直将等待下去 |
jstack命令分析
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
[root@localhost ~]# jstack 133992020-01-05 10:09:42Full thread dump OpenJDK 64-Bit Server VM (25.232-b09 mixed mode):"Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007f5bf0001000 nid=0x3477 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007f5c1804b800 nid=0x3458 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f5c18149000 nid=0x3462 waiting for monitor entry [0x00007f5c1cac7000] java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f5c18147000 nid=0x3461 waiting for monitor entry [0x00007f5c1cbc8000] java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f5c18117800 nid=0x345f runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f5c18114800 nid=0x345e waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f5c18105800 nid=0x345d waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f5c18103800 nid=0x345c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f5c180da000 nid=0x345b in Object.wait() [0x00007f5c1d62a000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e3408ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x00000000e3408ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f5c180d5000 nid=0x345a in Object.wait() [0x00007f5c1d72b000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e3406c00> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000e3406c00> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"VM Thread" os_prio=0 tid=0x00007f5c180cb800 nid=0x3459 runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007f5c1811a000 nid=0x3460 waiting on condition JNI global references: 5Found one Java-level deadlock:============================="Thread-1": waiting to lock monitor 0x00007f5bfc0062c8 (object 0x00000000e3466bd0, a java.lang.Object), which is held by "Thread-0""Thread-0": waiting to lock monitor 0x00007f5bfc004e28 (object 0x00000000e3466be0, a java.lang.Object), which is held by "Thread-1"Java stack information for the threads listed above:==================================================="Thread-1": at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)"Thread-0": at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) |
在输出的信息中,已经看到,发现了1个死锁,关键看这个:
|
01
02
03
04
05
06
07
08
09
10
|
"Thread-1": at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)"Thread-0": at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) |
可以清晰的看到:
Thread2获取了 <0x00000000e3466be0> 的锁,等待获取 <0x00000000e3466bd0> 这个锁
Thread1获取了 <0x00000000e3466bd0> 的锁,等待获取 <0x00000000e3466be0> 这个锁
由此可见,发生了死锁。
更多java学习资料可关注:itheimaGZ获取
【JVM】面试题之死锁及问题是怎么定位的更多相关文章
- 史上最全!2020面试阿里,字节跳动90%被问到的JVM面试题(附答案)
前言:最近老是收到小伙伴的私信问我能不能帮忙整理出一份JVM相关的面试题出来,说自己在大厂去面试的时候这一块问的是特别多的,每次自己学的时候每次都学不到重点去.这不他来了,一份详细的JVM面试真题给大 ...
- JVM面试题(史上最强、持续更新、吐血推荐)
文章很长而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三部 ...
- 这道面试必问的JVM面试题70%的Java程序员会做错
前言 聊聊JVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别. JVM可以说和我们是老朋友了 ...
- 两道JVM面试题,竟让我回忆起了中学时代!
作者:肥朝 原文链接:https://mp.weixin.qq.com/s/4wJ6ANal0blLOseasfIuVw 中学授课模式 考虑到可能有部分粉丝对JVM参数不清楚,所以我们参照中学的授课模 ...
- JVM 面试题汇总
JVM 面试题汇总 1.什么是 JVM?它有什么作用? 答:JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,顾名思义它是一个虚拟计算机,也是 Java 程序能够实现跨平 ...
- 常见JVM面试题及答案整理
常见JVM面试题及答案整理 1.什么情况下会发生栈内存溢出 2.JVM内存模型 3.JVM内存为什么要分成新生代,老年代,持久代.新生代中为什么要分为Eden和Survivor. 3.1共享内存区划分 ...
- 面试半年,凭借这份JVM面试题,我终于拿到了字节跳动的offer!
内存区域 虚拟机栈生命周期与线程相同,描述的是Java 方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存取局部变量表.操作数栈.动态链接.方法出口等信息本地方法栈与虚拟机栈作用相似,只 ...
- 大厂必问的JVM面试题
本文目录: 讲一下JVM内存结构? 程序计数器 虚拟机栈 本地方法栈 堆 方法区 运行时常量池 直接内存 Java对象的定位方式 说一下堆栈的区别? 什么情况下会发生栈溢出? 类文件结构 什么是类加载 ...
- 014 JVM面试题
转自:http://www.importnew.com/31126.html 本文从 JVM 结构入手,介绍了 Java 内存管理.对象创建.常量池等基础知识,对面试中 JVM 相关的基础题目进行了讲 ...
随机推荐
- 12 Spring Data JPA:springDataJpa的运行原理以及基本操作(上)
spring data jpaday1:orm思想和hibernate以及jpa的概述和jpa的基本操作 day2:springdatajpa的运行原理 day2:springdatajpa的基本操作 ...
- java的io字符流关闭和刷新.flush();
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中. 但是关闭的流对象,是无法继续写出数据 的.如果我们既想写出数据,又想继续使用流,就需要 flush 方法了. flush :刷新缓冲区, ...
- 使用conda管理python环境
一.动机 最近打算折腾vn.py,但只有py27版本的,因为一向习惯使用最新稳定版的,所以不得不装py27的环境,不得不说 Python的全局锁真的很烦. 身为懒癌患者,必然使用全功能的anacond ...
- top 命令中的VIRT,RES,SHR ,MEM区别
VIRT 表示进程的虚拟(地址)空间大小,其包含进程实际使用的大小(申请的堆栈), 使用mmap映射的大小,包括外设RAM, 还有映射到本进程的文件(例如动态库),还有进程间的共享内存.所以VIRT ...
- 关于前端CSS的总结
CSS语法 CSS语言的基本单位是样式声明:propertyName : value ; CSS语言的使用方式: 1.把CSS样式声明作为HTML标签的style属性值.2.使用CSS选择器 CSS常 ...
- Opencv笔记(十四)——边缘检测算法canny
简介 Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法,它是由很多步构成的算法. 最优边缘检测的三个主要评价 ...
- tesseract系列(2) -- tesseract的使用
上文说了怎么编译成库,这次说说怎么使用,先验证下编译出来的结果. 下图是debug生成的文件,里面有个tesseract的应用程序. cmd进入目录下,执行命令:tesseract eurotext. ...
- Windows系统清理
@echo off del/f/s/q %systemdrive%\*.tmp del/f/s/q %systemdrive%\*._mp del/f/s/q %systemdrive%\*.log ...
- 【转】nginx如何设置防盗链
转自博客园作者:howhy,文章地址:nginx如何设置防盗链.大佬写的甚好,在此备份一下 关于nginx防盗链的方法网上有很多教程,都可以用,但是我发现很多教程并不完整,所做的防盗链并不是真正的彻底 ...
- Centos内核更新
内核更新操作后面补上.暂时记录删除多余内核操作 删除卸载多余内核 1.系统启动时,选择需要保留的内核进入系统,通过uname -a命令查看当前内核版本,以防误删 2. 使用rpm -qa | grep ...