mysql死锁占用线程池_Java 线程池死锁问题

一、线程池死锁

1、资源互斥死锁

这种死锁是最常见的经典死锁,假定存在 A、B 2个任务,A需要B的资源,B需要A的资源,双方都无法得到时便出现了死锁。

//首先我们先定义两个final的对象锁.可以看做是共有的资源.

final Object lockA = new Object();

final Object lockB = new Object();

//生产者A

class ProductThreadA implements Runnable{

@Override

public void run() {

//这里一定要让线程睡一会儿来模拟处理数据 ,要不然的话死锁的现象不会那么的明显.这里就是同步语句块里面,首先获得对象锁lockA,然后执行一些代码,随后我们需要对象锁lockB去执行另外一些代码.

synchronized (lockA){

//这里一个log日志

Log.e("CHAO","ThreadA lock lockA");

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (lockB){

//这里一个log日志

Log.e("CHAO","ThreadA lock lockB");

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

//生产者B

class ProductThreadB implements Runnable{

//我们生产的顺序真好好生产者A相反,我们首先需要对象锁lockB,然后需要对象锁lockA.

@Override

public void run() {

synchronized (lockB){

//这里一个log日志

Log.e("CHAO","ThreadB lock lockB");

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (lockA){

//这里一个log日志

Log.e("CHAO","ThreadB lock lockA");

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

//这里运行线程

ProductThreadA productThreadA = new ProductThreadA();

ProductThreadB productThreadB = new ProductThreadB();

Thread threadA = new Thread(productThreadA);

Thread threadB = new Thread(productThreadB);

threadA.start();

threadB.start();

2、Submit递归调用死锁

原理是在固定的线程池数量中,不断的submit 任务,然后等待返回结果,但是线程池数量是固定的,从头到尾所有的线程没执行完成,某次submit时就没有足够的线程来处理任务,所有任务都处于等待。

ExecutorService pool = Executors.newSingleThreadExecutor(); //使用一个线程数模拟

pool.submit(() -> {

try {

log.info("First");

pool.submit(() -> log.info("Second")).get();

//上一个线程没有执行完,线程池没有线程来提交本次任务,会处于等待状态

log.info("Third");

} catch (InterruptedException | ExecutionException e) {

log.error("Error", e);

}

});

3、线程池线程size不足造成的死锁

该类死锁一般是把一个线程池用于多个任务。

假定A,B 两个业务各需要2各线程处理业务,任务内部存在互相没有关联的lock,为了方便重用线程池,我们使用了一个线程池,最大线程数设置为2。

情形一:A,B有序执行,不会造成死锁

情形二: A、B并发执行,造成死锁

情形二出现的原因是A,B各分配了一个线程,当他们执行的条件都不满足的时处于wait状态,这时线程池没有更多的线程提供,将导致A、B处于死锁。

4、RejectedExecutionHandler 使用不当造成的死锁

一般处理任务时,触发该handler的情况分为2类,主要是线程关闭和线程队列不够,如果线程池shutdown关闭之后,我们尝试在该Handler中重新加入任务到线程池,那么会造成循环死锁问题。

二、解决方案

前两类死锁只要规范编码,找到相应的机制即可解决,我们这里主要介绍第三类问题解决方法,常见的方法如下3种

1、有序执行

2、不要共用同一线程池

3、使用公共锁资源的wait(long timeout)机制,让线程池超时后通过其他机制弥补这种问题

4、如果过于担心线程池不能回收,建议使用keepaliveTime+allowCoreThreadTimeOut,回收线程但不影响线程状态,可以继续提交任务。

三、notify和wait机制注意事项

notify和wait锁定的是调用此类方法的对象,因此一定注意使用统一资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值