高并发之-死锁

死锁代码 

package com.zy.concurent;

public class DeadLock {

    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        Thread thread1 = new Thread(new DeadLockRunalbe(obj1, obj2, 1, 2, true));
        thread1.setName("thread1");
        thread1.start();
        Thread thread2 = new Thread(new DeadLockRunalbe(obj1, obj2, 2, 1, false));
        thread2.setName("thread2");
        thread2.start();
    }

    /**
     * 线程死锁等待演示
     */
    public static class DeadLockRunalbe implements Runnable {
        Object object1;
        Object object2;
        int a, b;
        boolean flag;

        public DeadLockRunalbe(Object obj1, Object obj2, int a, int b, boolean flag) {
            this.object1 = obj1;
            this.object2 = obj2;
            this.a = a;
            this.b = b;
            this.flag = flag;
        }

        @Override
        public void run() {
            try {
                if (flag) synchronized (object1) {
                    Thread.sleep(100);
                    synchronized (object2) {
                        System.out.println(a + b);
                    }
                }
                else synchronized (object2) {
                    Thread.sleep(100);
                    synchronized (object1) {
                        System.out.println(a + b);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

通过jstack查看死锁信息:

通过jps -l查看死锁的进程ID:

jstack -l 8932查看死锁进程:

E:\project\interview\src\main\java\com\zy\concurent>jstack -l 8932
2020-03-15 16:21:50
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.192-b12 mixed mode):

"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x00000000030a3800 nid=0x1184 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"thread2" #13 prio=5 os_prio=0 tid=0x000000001e7c1000 nid=0x4390 waiting for monitor entry [0x000000002038e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.zy.concurent.DeadLock$SynAddRunalbe.run(DeadLock.java:45)
        - waiting to lock <0x000000076b0f7480> (a com.zy.concurent.DeadLock$Obj1)
        - locked <0x000000076b0f9548> (a com.zy.concurent.DeadLock$Obj2)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"thread1" #12 prio=5 os_prio=0 tid=0x000000001e7c0000 nid=0x728 waiting for monitor entry [0x000000002028f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.zy.concurent.DeadLock$SynAddRunalbe.run(DeadLock.java:39)
        - waiting to lock <0x000000076b0f9548> (a com.zy.concurent.DeadLock$Obj2)
        - locked <0x000000076b0f7480> (a com.zy.concurent.DeadLock$Obj1)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001e636800 nid=0x46b8 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001e640800 nid=0x4548 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001e63e000 nid=0x1a0c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001e63b000 nid=0x3b44 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001e633000 nid=0x2120 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001e602000 nid=0x3d88 runnable [0x000000001fb8e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        - locked <0x000000076b24fa98> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.io.BufferedReader.readLine(BufferedReader.java:324)
        - locked <0x000000076b24fa98> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:61)

   Locked ownable synchronizers:
        - None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001e53c800 nid=0x40e4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001e592800 nid=0x46f8 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000000319a800 nid=0x4d4 in Object.wait() [0x000000001f88f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076af88ed0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x000000076af88ed0> (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)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001e523000 nid=0x2754 in Object.wait() [0x000000001f78f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076af86bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x000000076af86bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=2 tid=0x000000001e502800 nid=0x2014 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000030b8800 nid=0x4524 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000030ba000 nid=0x4568 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000030bc000 nid=0x17c4 runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000030be800 nid=0x273c runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000030c0800 nid=0x3be0 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000030c1800 nid=0x338c runnable

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00000000030c5000 nid=0x514 runnable

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00000000030c6000 nid=0x3f44 runnable

"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x00000000030c7000 nid=0x24b4 runnable

"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x00000000030c8800 nid=0x472c runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000000001e660800 nid=0x44f8 waiting on condition

JNI global references: 12


Found one Java-level deadlock:
=============================
"thread2":
  waiting to lock monitor 0x000000001ce43728 (object 0x000000076b0f7480, a com.zy.concurent.DeadLock$Obj1),
  which is held by "thread1"
"thread1":
  waiting to lock monitor 0x000000001ce42288 (object 0x000000076b0f9548, a com.zy.concurent.DeadLock$Obj2),
  which is held by "thread2"

Java stack information for the threads listed above:
===================================================
"thread2":
        at com.zy.concurent.DeadLock$SynAddRunalbe.run(DeadLock.java:45)
        - waiting to lock <0x000000076b0f7480> (a com.zy.concurent.DeadLock$Obj1)
        - locked <0x000000076b0f9548> (a com.zy.concurent.DeadLock$Obj2)
        at java.lang.Thread.run(Thread.java:748)
"thread1":
        at com.zy.concurent.DeadLock$SynAddRunalbe.run(DeadLock.java:39)
        - waiting to lock <0x000000076b0f9548> (a com.zy.concurent.DeadLock$Obj2)
        - locked <0x000000076b0f7480> (a com.zy.concurent.DeadLock$Obj1)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

可以看到:

 java中几种工具的介绍:

jstack

jstack是java虚拟机自带的一种堆栈跟踪工具。

jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因。如线程间死锁、死循环、请求外部资源导致长时间等待等。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

常用命令:

jstack -l pid

jstack -m pid

jps:

java提供的一个显示当前所有java进程pid命令。适合在Linux/unix平台简单查看当前java进程的一些简单情况。

常用:jps -l

高并发环境下,MySQL的死锁问题常常会导致数据库性能下降甚至服务不可用。死锁的发生通常是由于多个事务在并发执行时相互等待对方持有的资源,从而形成循环依赖[^1]。为了有效分析和解决这类问题,需要从以下几个方面入手: ### 1. 死锁的分析方法 #### 1.1 查看死锁日志 MySQL 提供了 `SHOW ENGINE INNODB STATUS` 命令,可以用来查看最新的死锁信息。通过该命令,可以获取到死锁发生时各个事务的详细等待情况,包括每个事务当前持有的和等待的。这对于定位死锁的根本原因非常关键[^4]。 #### 1.2 SQL 加分析 在高并发场景下,某些 SQL 语句可能会对多个索引加,尤其是在涉及多个字段的更新操作时。例如,`UPDATE` 语句可能先对某个索引加,然后再对另一个索引加。如果多个事务以不同的顺序对这些索引加,就可能导致死锁。因此,分析 SQL 语句的加顺序是解决死锁问题的重要步骤[^5]。 ### 2. 死锁的解决方案 #### 2.1 调整事务的执行顺序 为了避免死锁,可以在设计事务时尽量保证所有事务以相同的顺序访问资源。例如,如果多个事务都需要访问 `user_id` 和 `item_id` 这两个字段,可以统一规定事务必须先访问 `user_id`,再访问 `item_id`,从而避免不同事务以不同顺序加导致的循环等待[^5]。 #### 2.2 减少事务的粒度 事务的执行时间越长,持有的时间也就越长,从而增加了与其他事务发生冲突的可能性。因此,可以通过优化事务逻辑,减少事务中涉及的操作数量,缩短事务的执行时间,降低死锁发生的概率。 #### 2.3 使用乐观或重试机制 在某些场景下,可以考虑使用乐观(Optimistic Locking)来替代悲观。乐观通常通过版本号(Version)或时间戳(Timestamp)来控制并发更新,只有在提交时才会检查是否有冲突。如果检测到冲突,可以抛出异常并由客户端决定是否重试。这种方式可以有效减少的竞争,降低死锁的发生概率。 #### 2.4 避免不必要的索引更新 在执行 `UPDATE` 语句时,应尽量避免对不必要的字段进行更新。例如,如果某个字段的值在大多数情况下不会发生变化,可以在应用层判断其值是否需要修改,避免无意义的更新操作,从而减少对索引的加次数。 ### 3. 示例:事务加顺序不一致导致死锁 假设存在三个事务,分别执行以下 `UPDATE` 语句: - 事务 A: `UPDATE table SET column1 = value1 WHERE user_id = 100;` - 事务 B: `UPDATE table SET column2 = value2 WHERE item_id = 200;` - 事务 C: `UPDATE table SET column3 = value3 WHERE user_id = 100;` 在这种情况下,事务 A 和 C 可能会先对 `user_id` 索引加,再对 `item_id` 或其他索引加,而事务 B 则可能先对 `item_id` 索引加,再对 `user_id` 索引加。如果这些事务并发执行,并且加顺序不一致,就可能导致死锁[^5]。 ### 4. 示例代码:乐观的实现 以下是一个使用乐观的简单示例,通过版本号来控制并发更新: ```sql -- 假设有一个 users,包含 id、name 和 version 字段 START TRANSACTION; -- 查询当前版本号 SELECT name, version FROM users WHERE id = 1; -- 更新操作前检查版本号 UPDATE users SET name = 'new_name', version = version + 1 WHERE id = 1 AND version = current_version; COMMIT; ``` 如果在更新时发现版本号不匹配(即其他事务已经修改了该记录),则说明发生了冲突,应用层可以选择重试操作。 ### 5. 预防死锁的最佳实践 - **统一加顺序**:确保所有事务按照相同的顺序访问资源,避免因加顺序不一致而导致死锁- **减少事务执行时间**:尽量在事务中执行必要的操作,减少事务的执行时间和的持有时间。 - **合理设计索引**:确保查询语句能够高效地使用索引,减少不必要的竞争。 - **使用合适的隔离级别**:根据业务需求选择适当的事务隔离级别,避免过高的隔离级别导致更多的竞争。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值