MySQL中死锁相关的问题
死锁
概念:当A事务拥有锁1需要锁2,同时B事务拥有锁2需要锁1的时候,两个线程就进入了天荒地老的循环等待,这就是死锁。
预防死锁:两种办法
- 设定锁等待时间:如果超过一定时间没有获取到锁就暂时放弃,然后回滚,此时会自动释放当前事务持有的锁
- 被锁时发起死锁检测:当一个线程被锁的时候就要找到他正在等待释放锁的线程,再递归着去找这个线程等待的线程,如果发现环就证明死锁了,那该回退就回退、该释放就释放。死锁检测还是挺耗时的,如果是简单的两个事务成环那两下就判断出来了,但一般没死锁要递归判断很多次,几乎是个O(n)的操作,这导致死锁检测占用很多CPU资源,虽然没死锁了但是事务又处理不了几个。
场景题:怎么解决热点行更新导致的性能问题?三个办法
- 关掉死锁检测:如果你能确保这个业务一定不会出现死锁,可以临时关闭死锁检测
- 控制并发度:控制更新同一行的线程的数量,降低死锁检测的成本
- 一个数据行改成逻辑上的多个数据行来减少锁冲突。比如银行账户余额这一行记录,可以分成10行记录的和,冲突概率就减小为 1/10,降低发生冲突的线程数,降低死锁检测的成本。
写一个死锁的例子
public class DeadLock implements Runnable{
private static final Object lock1=new Object();
private static final Object lock2=new Object();
private int flag;
public DeadLock(int flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag==1)
{
synchronized (lock1)
{
System.out.println(Thread.currentThread().getName()+"获取lock1并希望获得lock2");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2)
{
System.out.println(Thread.currentThread().getName()+"获取lock2");
}
}
}
else
{
synchronized (lock2)
{
System.out.println(Thread.currentThread().getName()+"获取lock2并希望获得lock1");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1)
{
System.out.println(Thread.currentThread().getName()+"获取lock1");
}
}
}
}
public static void main(String [] args){
DeadLock d1=new DeadLock(0);
DeadLock d2=new DeadLock(1);
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
// t1.run();
// t2.run();
// 不可以用run(),因为run()会等待线程执行完才能执行下一个线程,不是并发的
t1.start();
t2.start();
}
//输出结果
//Thread-0获取lock2并希望获得lock1
//Thread-1获取lock1并希望获得lock2
} #Java开发##春招##实习##笔试题目##MySQL##学习路径##后端开发#
查看3道真题和解析
叮咚买菜工作强度 229人发布