如何解决多线程造成的数据库死锁
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何解决多线程造成的数据库死锁相关的知识,希望对你有一定的参考价值。
java在启动多线程操作数据库时出现异常“”
程序执行步骤:
1、创建三个List结合。
2、for循环开始三条线程。
3、将三个集合交给三条线程处理。
4、每条线程循环List集合对两张表处理:
描述:数据库为oracle,一张主表,一张从表,主外建关联。
线程执行规则,先查主表是否存此条数据,如果存在先删除两张表的此条数据,在插入与此条数据主键一样的一条数据。
执行结果:java.sql.SQLException: ORA-00060: 等待资源时检测到死锁
只有部分数据入库了,只能通过sql语句杀掉锁。
请问高人怎样设计程序能避免这种情况?
1、程序方面优化算法(如有序资源分配法、银行算法等),在一个程序里,能不用多线程更新同一张数据库表 尽量不要用,如果要用,其避免死锁的算法就很复杂。
2、数据库方面设置等待超时时间
3、发生死锁后直接KILL掉数据库进程
参考资料:http://baike.baidu.com/view/121723.html?wtp=tt
参考技术A 这个感觉不能用多线程吧,查询可以使用,用到删除不行。死锁的概念以及处理方式
死锁定义
在多线程编程中(两个或两个以上的线程)因为资源抢占而早场的线程无线等待的问题
线程和锁的关系(一对多)
- 一个线程可以拥有多把锁
- 一把锁只能被一个线程锁拥有
手写死锁代码
/**
* Created with IntelliJ IDEA.
* Description:死锁
* User: starry
* Date: 2021 -05 -09
* Time: 10:00
*/
public class ThreadDemo36 {
public static void main(String[] args) {
//锁A(资源A)
Object lockA = new Object();
//锁B(资源B)
Object lockB = new Object();
//线程1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程1:得到了锁A");
try {
//休眠1s,让线程2先得到锁B
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:等待获取锁B");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程1:得到了锁B");
}
}
}
},"t1");
t1.start();
//创建并启动线程2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockB) {
System.out.println("线程2:得到了锁B");
try {
//休眠1s,让线程1先得到锁A
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2:等待获取锁A");
//尝试获取锁B
synchronized (lockA) {
System.out.println("线程2:获取到锁A");
}
}
}
},"t2");
t2.start();
}
}
可以看到这时已经发生死锁了,程序一直执行不下去
检查测死锁工具
- jconsole 工具
- jvisualvm 工具
- jmc 工具
具体使用请看我这篇文章:https://blog.csdn.net/starry1441/article/details/116742308
死锁造成的四个条件(同时满足)
- 互斥条件(一个资源只能被一个线程持有,当被一个线程持有之后就不能被其他线程持有)
- 请求拥有条件(一个线程持有了一个资源之后,又试图请求另一个资源)
- 不可剥夺条件(一个资源被一个线程拥有之后,如果这个线程不释放此资源,那么其他线程不能强制获得此资源)
- 环路等待条件(多个线程在获取资源时,形成了一个环形链条)
如何解决死锁
从以下两个条件如手,修改以下条件任意一个:
- 请求拥有条件
- 环路等待条件(最易实现)
我们将线程1 先获取 锁A和锁B,然后再让线程2 获得锁A和锁B,修改环路等待条件,我们来试一试吧
/**
* Created with IntelliJ IDEA.
* Description:解决死锁
* User: starry
* Date: 2021 -05 -09
* Time: 10:00
*/
public class ThreadDemo37 {
public static void main(String[] args) {
//锁A(资源A)
Object lockA = new Object();
//锁B(资源B)
Object lockB = new Object();
//线程1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程1:得到了锁A");
try {
//休眠1s,让线程2先得到锁B
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:等待获取锁B");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程1:得到了锁B");
}
}
}
},"t1");
t1.start();
//创建并启动线程2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程2:得到了锁B");
try {
//休眠1s,让线程1先得到锁A
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2:等待获取锁A");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程2:获取到锁A");
}
}
}
},"t2");
t2.start();
}
}
此时程序正常的结束了,线程1和线程2都分别获取到了锁A锁B
以上是关于如何解决多线程造成的数据库死锁的主要内容,如果未能解决你的问题,请参考以下文章