欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java多线程-死锁和死锁避免

程序员文章站 2022-05-22 11:21:21
...

一、死锁产生的四个必要条件

  • 互斥条件:某个资源只能被一个进程使用,其他线程请求资源只能等待,直到当前线程释放资源(不可优化项)
  • 占有并等待:进程已经保持一个资源,但是又提出了新要求,而这个资源被其他线程,自己保持的资源不被释放
  • 不可枪占条件:一个进程的资源未使用完,不会释放资源
  • 循环等待:线程获取资源存在一个循环链

二、死锁避免解决方案

  • 破坏互斥:对于共享资源,我们要破坏互斥条件,例如多线程对于只读文件的读取操作
  • 破坏占有并等待:当一个进程申请一个资源时,它不能占有其他资源。可以通过两种方式实现,方式一一个进程在执行前需要申请其所需的所有的资源。方式二,进程在没有资源时才可以申请。两种方式都有着缺点是会造成资源浪费和进程饥饿发生
  • 破坏不可枪占条件:如果一个线程持有一些资源,那么如果继续请求其他资源的时候,发现不能请求成功,这个时候其他进程就可以枪占该进程的资源。
  • 采用合适的进程推进顺序造成线程-银行家算法

三、银行家算法避免死锁

四、 一个死锁实例

package Concurrence;

/**
 * Created by luckyboy on 2018/8/7.
 */
public class DeadLock {
    public static void main(String[] args){
        Common common = new Common();
        Thread7 thread7 = new Thread7(common);
        Thread8 thread8 = new Thread8(common);
        thread7.start();
        thread8.start();
    }
}
class Thread7 extends Thread{
    private Common common;
    public Thread7(Common common){
        this.common = common;
    }
    @Override
    public void run(){
        common.methodA();
    }
}
class Thread8 extends Thread{
    private Common common;
    public Thread8(Common common){
        this.common = common;
    }
    @Override
    public void run(){
        common.methodB();
    }
}
class Common{
    private Object obj1 = new Object();
    private Object obj2 = new Object();
    public void methodA(){
        synchronized (obj1){
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+"获取了当前obj1的锁");
                synchronized(obj2){
                    System.out.println(Thread.currentThread().getName()+"获取了obj2的锁");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    public void methodB(){
        synchronized (obj2){
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+"获取了当前obj2的锁");
                synchronized(obj1){
                    System.out.println(Thread.currentThread().getName()+"获取了obj1的锁");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

输出结果

五、线程运行查看工具jstack

打开PowerShell,运行下面的命令

PS C:\WINDOWS\system32> jstack

输出结果如下

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [aaa@qq.com]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

运行上面的语句我们可以获取一个线程的id、优先级、nid、是否是守护线程、线程的运行转态。
我们运行上面的DeadLockTest,然后去任务管理器查看我们的进程ID
java多线程-死锁和死锁避免

在PowerShell中输入下面的命令

PS C:\WINDOWS\system32> jstack -l 11052

得到的输出结果如下

2018-08-07 09:21:39
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000003182800 nid=0x2f28 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Thread-1" #12 prio=5 os_prio=0 tid=0x000000001b88e000 nid=0x27dc waiting for monitor entry [0x000000001c5ff000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at Concurrence.DeadLock.methodB(DeadLockTest.java:59)
        - waiting to lock <0x0000000780617130> (a java.lang.Object)
        - locked <0x0000000780617140> (a java.lang.Object)
        at Concurrence.Thread8.run(DeadLockTest.java:33)

   Locked ownable synchronizers:
        - None

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001b88b000 nid=0x11c0 waiting for monitor entry [0x000000001c4ff000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at Concurrence.DeadLock.methodA(DeadLockTest.java:45)
        - waiting to lock <0x0000000780617140> (a java.lang.Object)
        - locked <0x0000000780617130> (a java.lang.Object)
        at Concurrence.Thread7.run(DeadLockTest.java:23)

   Locked ownable synchronizers:
        - None
//......这里省略了GC线程和一些daemon线程信息
Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x0000000003278618 (object 0x0000000780617130, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000327ab38 (object 0x0000000780617140, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at Concurrence.DeadLock.methodB(DeadLockTest.java:59)
        - waiting to lock <0x0000000780617130> (a java.lang.Object)
        - locked <0x0000000780617140> (a java.lang.Object)
        at Concurrence.Thread8.run(DeadLockTest.java:33)
"Thread-0":
        at Concurrence.DeadLock.methodA(DeadLockTest.java:45)
        - waiting to lock <0x0000000780617140> (a java.lang.Object)
        - locked <0x0000000780617130> (a java.lang.Object)
        at Concurrence.Thread7.run(DeadLockTest.java:23)

Found 1 deadlock.

线程信息解读

字段 信息解读
Thread-1 线程名称
prio=5 线程优先级
tid=0x000000001b88e000 线程id
java.lang.Thread.State: BLOCKED java线程状态为阻塞状态
locked <0x0000000780617140> 获得了<0x0000000780617140>这个对象
waiting to lock <0x0000000780617140> 等待获取的对象的锁