什么是deadlock?.如果没有外力,他们将无法前进。死锁的四个必要条件大家耳熟能详:互斥条件:进程要求独占控制所分配的资源,即某一资源在一段时间内只被一个进程占用。这时,如果其他进程请求资源,请求进程只能等待。非剥夺条件:进程获得的资源在用完之前,不能被其他进程强行夺走,即只能由获得资源的进程释放。请求和持有条件:进程至少持有一个资源,但又提出新的资源请求,且该资源已被其他进程占用。这时候请求进程被阻塞了,但是它并没有放过已经获得的资源。循环等待条件:进程资源存在循环等待链,链中每个进程获得的资源同时被链中的下一个进程请求。相应地,如果想在程序运行之前就防止死锁(也称“死锁预防”),就必须设法破坏死锁的四个必要条件之一。破坏互斥条件:允许系统资源共享,则系统不会进入死锁状态。这个方案不太可行,因为有些资源根本不能同时访问,比如打印机。非剥夺条件的破坏:当一个已经占有了一些不可剥夺资源的进程在请求新的资源时不能满足时,它必须释放所有占有的资源,并在以后需要时重新申请。这种方式常用于状态易于保存和恢复的资源,如CPU寄存器、内存资源等,一般不能用于打印机等资源。销毁请求保持条件:采用预静态分配方式,即进程在运行前已经申请了所有需要的资源,直到其资源不满足才会投入运行。一旦运行起来,这些资源就一直归它所有,不会再有其他的资源请求,这样就可以保证系统不会死锁。破坏循环等待条件:使用顺序资源分配方式。首先对系统中的资源进行编号,规定每个进程必须按照编号递增的顺序申请资源,同一类型的资源可以一次性申请。也就是说,只要一个进程申请了资源分配,在后续的资源申请中,该进程只能申请比之前编号更大的资源。只看文中列出的要点,一定还不能完全理解。下面将举例说明给大家。Java写死锁这绝对是面试中TOP2的Java手写题!!!除了大家熟知的手写单例模式外,手写死锁可能会被一些朋友忽略。道理其实很简单。我们申请两个资源,开两个线程。每个线程都持有其中一个资源,互相请求对方的资源,就构成了死锁。MySQLdeadlockMySQL经典死锁案例我们来看一个MySQL经典死锁案例:从A账户向B账户转50元的同时,B账户也向A账户转30元。一般情况下,如果只有一次操作,A向B转账50元可以一笔交易完成,先获取用户A和用户B的余额,因为后面需要修改这两个数据,所以需要用writelock(forUPDATE)加锁,防止其他交易变更导致我们的变更丢失,造成脏数据,但是如果A转账给B,B同时转账给A,就是两笔交易,可能会出现死锁:1)用户A转账50元给用户B,需要在程序中启动事务1执行SQL,获取A的余额,同时锁定A的数据。2)用户B给用户A转账30元,需要在程序中启动事务2执行SQL,获取B的余额,同时锁定B的数据。3)执行事务1中剩余的SQL,此时事务1无法获得B的锁,即selectforupdate会被阻塞;4)同理,事务2继续执行剩下的SQL。A请求的锁也是无法获得的。事务1和事务2在等待对方获取锁的过程中,导致两个事务都挂了阻塞,最后抛出获取锁超时的异常。MySQL死锁如何解决要解决上面的死锁问题,我们可以从死锁的四个必要条件入手。其指导思想其实很明确:就是保证同时发生A到B转账和B到A转账这两个事务中只有一个能够成功获取到锁。由于互斥和非剥夺是锁功能的本质,是不可修改的,所以我们尝试从另外两个条件来解决。1)破坏“requestandhold”条件:A和B之间的操作用同一个锁加锁(比如用Redis分布式锁,A和B之间的锁的key表示为A:B,可以使id小的用户在前,id大的用户在后。这样设计key,如果有分库分表,可以使用hashcode进行比较)确保即A转账给B,B转账给A,一次只能有一笔交易成功获取锁。2)破坏“循环等待”条件:先获取小锁,再获取大锁(所谓小锁还是大锁,也可以简单的根据用户id区分,先请求id较小的用户,然后请求id较大的用户)。比如A.id
