java死锁

死锁:指俩个或以上的线程循环等待其他线程占用的资源,但在未获取资源时又不放弃自己的资源。这种情况下如果没有外力作用,将永远等待下去。
比如:有A ,B两个资源,甲,乙两个线程。
甲——>A 甲占有A
乙——>B 乙占有B
这时候甲请求B,乙请求A,但是甲没请求到B的时候又不愿放弃A,乙没请求到A的时候不愿放弃B。两个进程都不能正常执行,这样两者就会无限的等待下去。
产生死锁的条件:
1:互斥条件。某个资源某刻只能由一个线程占用。
2:不可抢占条件。进程所获得资源在未使用完毕之前,资源申请者不能强行获取。
3:占用申请条件。
4:循环等待条件。
以上四个条件同时发生,即会产生死锁。
我们来看一下具体例子:

class Suo {
    static Object so1 = new Object();
    static Object so2 = new Object();
}

class DeadLocks implements Runnable {
    public boolean flag;
    public DeadLocks(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        if (flag) {
            while (true) {
                synchronized (Suo.so1) {//请求到so1并加锁
                    System.out.println("so1:"+ Thread.currentThread().getName());
                    synchronized (Suo.so2) {//请求so2,并加锁,由于so2被占用,故会一直等待
                        System.out.println("so2:"+ Thread.currentThread().getName());
                    }
                }
            }
        } else {
            while (true) {
                synchronized (Suo.so2) {//请求到so2并加锁
                    System.out.println("so2:"+ Thread.currentThread().getName());
                    synchronized (Suo.so1) {//请求到so1并加锁,由于so1被占用,故会一直等待
                        System.out.println("so1:"+ Thread.currentThread().getName());
                    }
                }
            }
        }
    }
}

测试:

public class JstackDemo {

    public static void main(String[] args) {
        Thread t1 = new Thread(new DeadLocks(true));
        Thread t2 = new Thread(new DeadLocks(false));
        t1.start();
        t2.start();
    }
}

输出:
so1:Thread-0
so2:Thread-1

只打印两行,就不在打印下去了。
我们使用jstack打印下jvm堆栈信息
这里写图片描述
直接就可以看出:在34行和45发生死锁。

那么如何避免死锁呢。
只要打破上述四个条件之一就可解除死锁。
算法:银行家算法。

死锁的恢复:
1系统重启。
2撤销进程,剥夺资源。

Java 死锁是多线程编程中一个重要且棘手的问题,下面从定义、产生原因、解决方案等方面进行介绍。 ### 定义 死锁指两个或多个线程互相持有对方所需的资源,并同时等待对方释放资源,导致程序无法继续执行。程序会陷入“僵局”状态,无法自行解锁,通常会导致程序无响应或者卡死,无法正常处理请求。每个线程都持有一个资源并且同时等待另一个资源,形成一种僵局,没有任何一个线程能够释放其持有的资源,也无法获得它所需的资源,程序停止响应 [^2]。 ### 产生原因 主要是资源竞争,每个线程持有一个资源的同时又去等待获取其他线程持有的资源,从而形成循环等待的局面。一旦出现死锁,整个程序既不会发生任何错误,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。Java 虚拟机没有提供检测,也没有采取任何措施来处理死锁的情况 [^2][^4]。 ### 解决方案 解决死锁要根据产生死锁的条件来进行: 1. **针对资源互斥**:可以根据代码逻辑去掉互斥锁逻辑,比如涉及金额的话用 `AtomicInteger`(原子操作)、`ThreadLocal`、CAS 乐观锁 [^3]。 2. **针对请求与保持条件**:可以用 `List` 集合将 2 个资源放在一个集合中,通过 `contains` 判断,如果集合中有元素,就用一个 boolean 变量标记 `false`,直到 2 个资源释放后,变量标记 `true`,后面的线程才能使用 [^3]。 3. **针对不可剥夺条件**:通过 `this.lock.tryLock(2, TimeUnit.SECONDS)` 设置时长锁等待 [^3]。 死锁发生后,通常只能通过人工干预来解决,比如重启服务或者杀死线程。所以只能在编码时避开可能出现死锁的问题,按照死锁发生的四个条件,破坏其中的一种就能避免死锁的发生,但互斥条件无法被破坏,因为它是互斥锁的基本约束 [^5]。 ```java import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class A extends Thread { private final Lock lock = new ReentrantLock(); // 设置锁 public boolean loop = true; public static Object object1 = new Object(); public static Object object2 = new Object(); public A(boolean loop) { this.loop = loop; try { this.lock.tryLock(2, TimeUnit.SECONDS); // 设置锁等待 } catch (InterruptedException e) { e.printStackTrace(); } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值