前言

之前面试的时候被问到死锁这块的问题,借着最近学习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. CentOS6.x/6.5/6.4/6.3/6.2/7.x 64位安装php5.2(使用YUM自动安装)

    默认情况下,CentOS6 64 bit 已经早已不支持php5.2.x ,但是某些php程序还需要zend optimizer支持,怎么办呢?目前大部分的yum repos 都已经不支持直接安装ph ...

  2. 题解 P2016 【战略游戏】

    题目 解法跟 dalao @real_ljs 类似,但没有用到递归 [分析] 题目相当于需要求覆盖这颗树需要的最小点数 用 \(Dp_{i,0/1}\) 表示在这棵树中,以 \(i\) 为根节点的子树 ...

  3. android studio 修改新建EmptyActivity默认布局

    https://www.jianshu.com/p/d4f201135097 打开你的Android Sudio安装目录,我的为D:\Program Files\Android\Android Stu ...

  4. c语言中指针和多维数组的理解

    1.复习指针和数组之间的特殊关系:不带方括号的数组名是一个指针,指向该数组的第一个元素. 2.多维数组: ][];//声明一个二维数组作为举例 a.理解方式1:可以将数组看成行和列构成,即理解成2行4 ...

  5. eclipse Java EE 与 Java 区别

    1. 综述 eclipse IDE 一般来说有三种可切换的模式 Java EE Java 调试 可直接下拉至底部看两者的比较. 2. Java Java 是带有用户界面的 基本IDE ,缺少数据库和w ...

  6. views层回顾

    目录 views层回顾 jsonResponse 2 大文件上传 3. cbv和fbv源码分析 4settings.py源码分析 5模板传值{{}} {%%} 6. 过滤器和标签和自定义 7模板的继承 ...

  7. Django内置标签

    在Django中也提供了大量Django自带的内置标签来供我们使用.标签的写法与过滤器的写法不同,标签是具有开始和结束的,例如:{% if  %}为开始标签,{% endif %}为结束标签. 可以查 ...

  8. SQL case when else 语句:选出年份等于1970的,选出的结果用科目和获奖者排序,同时把经济和化学2科放到最后:SELECT * FROM nobel_win WHERE year=1970 ORDER BY CASE WHEN subject IN ('Economics','Chemistry') THEN 1 ELSE 0 END ASC, subject, winner;

    SELECT * FROM nobel_win WHERE year=1970 ORDER BY  CASE WHEN subject IN ('Economics','Chemistry') THE ...

  9. Python——气象数据分析

    将对意大利北部沿海地区的气象数据进行分析与可视化.我们在实验过程中先会运用 Python 中 matplotlib 库的对数据进行图表化处理,然后调用 scikit-learn 库当中的的 SVM 库 ...

  10. 源码分析Dubbo服务消费端启动流程

    通过前面文章详解,我们知道Dubbo服务消费者标签dubbo:reference最终会在Spring容器中创建一个对应的ReferenceBean实例,而ReferenceBean实现了Spring生 ...