前言

之前面试的时候被问到死锁这块的问题,借着最近学习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锁定,所以发送了死锁。

[JavaScript] 纯文本查看 复制代码
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 的锁");
                }
            }
        }
    }
 
 
}
[Java] 纯文本查看 复制代码
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]# ll
total 27692
drwxr-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 TestDeadLock
Thread1 拿到 obj1 的锁
Thread2 拿到 obj2 的锁
#这里发生了死锁,程序一直将等待下去

jstack命令分析

[JavaScript] 纯文本查看 复制代码
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 13399
2020-01-05 10:09:42
Full 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: 5
 
 
Found 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个死锁,关键看这个:

[JavaScript] 纯文本查看 复制代码
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】面试题之死锁及问题是怎么定位的更多相关文章

  1. 史上最全!2020面试阿里,字节跳动90%被问到的JVM面试题(附答案)

    前言:最近老是收到小伙伴的私信问我能不能帮忙整理出一份JVM相关的面试题出来,说自己在大厂去面试的时候这一块问的是特别多的,每次自己学的时候每次都学不到重点去.这不他来了,一份详细的JVM面试真题给大 ...

  2. JVM面试题(史上最强、持续更新、吐血推荐)

    文章很长而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三部 ...

  3. 这道面试必问的JVM面试题70%的Java程序员会做错

    前言 聊聊JVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别. JVM可以说和我们是老朋友了 ...

  4. 两道JVM面试题,竟让我回忆起了中学时代!

    作者:肥朝 原文链接:https://mp.weixin.qq.com/s/4wJ6ANal0blLOseasfIuVw 中学授课模式 考虑到可能有部分粉丝对JVM参数不清楚,所以我们参照中学的授课模 ...

  5. JVM 面试题汇总

    JVM 面试题汇总 1.什么是 JVM?它有什么作用? 答:JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,顾名思义它是一个虚拟计算机,也是 Java 程序能够实现跨平 ...

  6. 常见JVM面试题及答案整理

    常见JVM面试题及答案整理 1.什么情况下会发生栈内存溢出 2.JVM内存模型 3.JVM内存为什么要分成新生代,老年代,持久代.新生代中为什么要分为Eden和Survivor. 3.1共享内存区划分 ...

  7. 面试半年,凭借这份JVM面试题,我终于拿到了字节跳动的offer!

    内存区域 虚拟机栈生命周期与线程相同,描述的是Java 方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存取局部变量表.操作数栈.动态链接.方法出口等信息本地方法栈与虚拟机栈作用相似,只 ...

  8. 大厂必问的JVM面试题

    本文目录: 讲一下JVM内存结构? 程序计数器 虚拟机栈 本地方法栈 堆 方法区 运行时常量池 直接内存 Java对象的定位方式 说一下堆栈的区别? 什么情况下会发生栈溢出? 类文件结构 什么是类加载 ...

  9. 014 JVM面试题

    转自:http://www.importnew.com/31126.html 本文从 JVM 结构入手,介绍了 Java 内存管理.对象创建.常量池等基础知识,对面试中 JVM 相关的基础题目进行了讲 ...

随机推荐

  1. jsp动作标签学习

    <jsp:useBean> <jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实 ...

  2. 【MySQL优化】数据库结构优化

    原则: 设计表结构,字段类型,最小化磁盘存储的空间,减少IO.数据库操作中最为耗时的操作就是 IO 处理,大部分数据库操作 90% 以上的时间都花在了 IO 读写上面.所以尽可能减少 IO 读写量,可 ...

  3. 吴裕雄--天生自然 JAVA开发学习:方法

    /** 返回两个整型变量数据的较大值 */ public static int max(int num1, int num2) { int result; if (num1 > num2) re ...

  4. Python重学记录1

    写下这个标题觉得可笑,其实本人2014年就自学过一次python,当时看的是中谷教育的milo老师的视频,也跟着写了一些代码,只是因为当时工作上用不到也就淡忘了.不过说实话当时的水平也很低下,本来也没 ...

  5. LeetCode Input Initial Code

    说明 LeetCode提供的样本输入,显示上是数组Array,而后台的实际测试用例则是树TreeNode,链表ListNode等. 如果你是在页面手撸代码直接提交的,那没什么影响. 如果你是在本地ID ...

  6. tif图片压缩

    tif图片在ImageIo.read获取时,返回为空,导致无法使用,百度了很久,很多人说jai可以,便去看了下,总结如下: public static void CompressPic(String ...

  7. 用FFmpeg+nginx+rtmp搭建环境实现推流

    Windows: 1.下载文件: 链接:https://pan.baidu.com/s/1c2LmIHHw-dwLOlRN6iTIMg 提取码:g7sj 2.解压文件: 解压到nginx-1.7.11 ...

  8. Linux之程序的开始和结束

    1.main函数由谁来调用 (1).编译链接时的引导代码. 操作系统下的应用程序其实是在main函数执行前也需要先执行一段引导代码才能去执行main函数,我们写应用程序时不用考虑引导代码的问题,编译链 ...

  9. drf三大认证补充

    频率认证 源码分析部分 def check_throttles(self, request): for throttle in self.get_throttles(): if not throttl ...

  10. LeetCode——1305. 两棵二叉搜索树中的所有元素

    给你 root1 和 root2 这两棵二叉搜索树. 请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序.. 示例 1: 输入:root1 = [2,1,4], root2 = [1,0 ...