死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的相互等待的现象;在无外力作用下,一直处于等待的状况; 学过操作系统的朋友应该都知道 * 死锁发生时的条件: * * (1)互斥条件:一个资源每次只能被一个进程使用。独木桥每次只能通过一个人。 * (2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。乙不退出桥面,甲也不退出桥面。 * (3)不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺。甲不能强制乙退出桥面,乙也不能强制甲退出桥面。 * (4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。如果乙不退出桥面,甲不能通过,甲不退出桥面,乙不能通过。 要想避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可; 学过操作系统的朋友知道 目前只有请求并持有和环路等待条件是可以被破会的; 1.造成死锁的原因其实和申请资源的顺序有很大关系; 使用资源申请的有序性原则就可以避免死锁,(按同一顺序访问对象) 加锁顺序 加锁时限 死锁检测 1 使用事务时,尽量缩短事务的逻辑处理过程,及早提交或回滚事务; (细化处理逻辑,执行一段逻辑后便回滚或者提交,然后再执行其它逻辑,直到事物执行完毕提交) 2 设置死锁超时参数为合理范围,如:3分钟-10分种;超过时间,自动放弃本次操作,避免进程悬挂; 3 优化程序,检查并避免死锁现象出现; 4 .对所有的脚本和SP都要仔细测试,在正是版本之前。 5 所有的SP都要有错误处理(通过@error) 6 一般不要修改SQL SERVER事务的默认级别。不推荐强行加锁 按同一顺序访问对象 如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。例如,如果两个并发事务获得 Supplier 表上的锁,然后获得 Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在 Supplier 表上。第一个事务提交或回滚后,第二个事务继续进行。不发生死锁。将存储过程用于所有的数据修改可以标准化访问对象的顺序。 避免事务中的用户交互 避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。 保持事务简短并在一个批处理中 在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。 使用低隔离级别 确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。 使用绑定连接 使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞。
ReentrantLock 锁常用于保证程序的人为顺序执行。 锁的种类分为8种: 乐观锁和悲观锁 公平锁和非公平锁 ReentrantLock true/false 独占锁(是一种悲观锁)和共享锁(是一种乐观锁) 可重入锁和自旋锁 乐观锁和悲观锁 乐观锁 (乐观锁一般会使用版本号机制或CAS(Compare-and-Swap,即比较并替换)算法实现 是一种有名的无锁算法) 这就是MySQL中的排他锁起了作用 排他锁又称为写锁 update goods set num = num - 1 WHERE id = 1001 and num > 0 悲观锁 在数据被处理前先对数据加锁 传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。