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##学习路径##后端开发#