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

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

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

二、死锁避免解决方案

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

三、银行家算法避免死锁

四、 一个死锁实例

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] [server_id@]<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
这里写图片描述

在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> 等待获取的对象的锁

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/81474748