Java多线程中的死锁

Java多线程中的死锁

死锁产生的原因

线程死锁是指由两个以上的线程互相持有对方所需要的资源,导致线程处于等待状态,无法往前执行。

当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源。在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

死锁产生的必要条件

  1. 互斥条件:进程对于锁分配的资源具有排他性,即一个资源只能被一个线程所拥有,直到该线程被释放
  2. 请求和保持条件:一个进程因为请求被占用资源而发生阻塞,对已获得的资源保持不放
  3. 不可剥夺条件:任何一个资源在没被该线程程释放之前,任何线程都没有办法剥夺占用
  4. 循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞

手写一个死锁

public class DeadLock {

    static Object a =   new Object();
    static Object b =   new Object();

    public static void main(String[] args) {
        new Thread(()->{
            synchronized (a){
                System.out.println(Thread.currentThread().getName()+"占用锁A,获取锁B");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b){
                    System.out.println(Thread.currentThread().getName()+"获取锁B");
                }
            }
        },"A").start();

        new Thread(()->{
            synchronized (b){
                System.out.println(Thread.currentThread().getName()+"占用锁A,获取锁B");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a){
                    System.out.println(Thread.currentThread().getName()+"获取锁B");
                }
            }
        },"B").start();
    }
}

验证死锁

Jstack命令

jps -l

显示当前系统的java进程情况及进程id,类似于linux中的ps -ef查看进程号

jstack 进程号。

jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息

解决死锁

产生死锁需要四个条件,那么,只要这四个条件中至少有一个条件得不到满足,就不可能发生死锁了。其中互斥条件是不可以破坏的,它是线程安全的基础

一、破坏请求和保持条件

  1. 如果需要多个资源,则一次性全部申请,无法申请,则等待。
  2. 在逻辑允许情况下,在使用完一个资源后,则释放当前资源。

二、破坏不可剥夺条件

当需要多个资源,只获得了部分资源,无法获得其他资源时,则释放所有资源;

三、破坏循环等待条件

给所有资源进行线性排序标号,在程序请求资源时,按顺序获取和使用资源。

解决死锁的方法有很多,只是举了几个例子

Tags:
Exit mobile version