什么是锁?死锁的三种情况及解决办法

简介

锁是计算机协调多个进程或线程并发访问某一资源的机制(避免发生资源争抢)。

锁的分类

  1. 对数据操作的粒度分
    1. 表锁:操作时,会锁定整个表,不会出现死锁。
    2. 行锁:操作时,会锁定当前操作行,会出现死锁。
存储引擎表锁行锁加锁方式
InnoDB支持支持在执行UPDATE、DELETE、INSERT语句时,自动给涉及的数据加排他锁,一般的SELECT语句不加任何锁
MyISAM支持不支持在执行SELECT前会自动给涉及的所有表加共享锁,在执行UPDATE、DELETE、INSERT等操作前,给涉及的表加排他锁
  1. 对数据操作的类型分
    1. 共享锁(Share Locks,读锁):事务A对数据加锁后,只能读取加锁的数据,不能读取其他数据,其他事务可以读取,均不能修改(增,删、改)。
    2. 排他锁(Exclusive Locks,写锁):事务A操作时,其他事务不能对数据对象读取和修改。
--表锁模式
--加表锁
lock table table_name read;--共享锁
lock table table_name write;--排他锁
--
--解锁
unlock table_name;
--行锁模式
--加行锁
select * from tab_name where...lock in share mode;--加共享锁(in share mode)
select * from tab_name where...for update;--加排他锁(for update)

提醒:共享锁可以多个事务同时对同一个数据加锁,排他锁一次性只能由一个事务对数据对象加锁

死锁的三种情况及解决办法

  1. 第一种情况:
    用户甲访问表A(锁住了A),然后访问表B;用户乙访问表B(锁住了B),然后访问表A;由于表B被用户乙锁住,用户甲必须等用户乙释放表B才能继续,同样由于表A被甲锁住,用户乙必须等用户甲释放表A才能继续,从而产生了死锁。
    解决办法:
    这种情况是由于程序的bug产生,应分析程序的逻辑,对于数据库的多表操作,应按照相同的顺序进行处理,尽量避免同时锁定两个资源。
  2. 第二种情况:
    用户甲查询一条记录,然后要修改这条记录;这时用户乙修改该条记录;此时用户甲事务里锁的性质欲由共享锁变为排他锁,而用户乙里的排他锁因为甲有共享锁存在,必须等甲释放掉共享锁,而甲因为乙的排他锁而无法变为排他锁也就不可能释放共享锁。
    解决办法:
    ①对于按钮等控件,单击后使它立即失效,不要让用户重复单击,避免同时对同一条记录进行操作。
    ②使用乐观锁、悲观锁进行控制
  3. 第三种情况:
    如果在事务中执行了一条不满足条件的update语句,则执行全表扫描,把行级锁提升为表级锁,多个这样的事务执行后,很容易产生死锁和阻塞。
    解决办法:
    SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,应建立相应的索引进行优化。
### 死锁的概念 死锁是指两个或多个进程在执行过程中,由于竞争资源或者相互通信而造成的一种阻塞现象,此时所有涉及的进程都无法向前推进[^3]。具体来说,当一组进程中的每一个都在等待仅由该组进程中的其他成员所占用的资源被释放时,则认为发生了死锁。 ### 操作系统层面的解决方案 操作系统提供了多种方式来应对可能出现的死锁情况: #### 1. 死锁预防 这种方法试图破坏形成死锁的一个必要条件——持有并等待、循环等待链路、互斥使用资源和非剥夺性分配。例如,可以规定任何请求新资源之前必须先放弃当前持有的全部资源,以此打破“持有并等待”的条件[^1]。 #### 2. 死锁避免 此策略是在每次分配资源前检查系统的状态是否会进入不安全区,即是否存在潜在的死锁定局面。银行家算法就是一个典型的例子,它能够预测未来的资源需求,并决定是否应该满足某个特定的任务请求以防止未来可能产生的死锁状况。 #### 3. 死锁检测与恢复 不同于上述两种主动防御的方式,这种方式允许暂时性的死锁存在,之后再通过周期性扫描发现死锁的存在并通过某种手段(如撤销部分作业)使受影响的过程恢复正常运行。对于那些未采取预防或避免措施的操作环境而言,这是唯一可行的选择[^2]。 ### 并发编程中的实践建议 为了减少并发程序中出现死锁的风险,在设计阶段就应该考虑以下几个方面: - **最小化共享资源的数量**:尽可能降低不同线程间共用的数据量。 - **合理规划获取/释放顺序**:确保所有的线程按照相同的顺序访问公共资源,这样就可以有效规避循环等待的发生。 - **设置超时机制**:给定时间内未能成功获得所需资源则自动回滚操作,从而避免无限期地处于等待状态。 ```java try { if (!lock.tryLock(5, TimeUnit.SECONDS)) { // 尝试加最多五秒 throw new RuntimeException("Could not acquire lock"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // 成功拿到后记得解 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值