总结避免死锁的几种方法

最近项目中用到一些多线程的知识,涉及到一个线程需要锁住多个资源的情况,这就会涉及到多线程的死锁问题。特此总结一下

死锁产生的方式有好几种,并不是只有一个线程涉及多个锁才会出现死锁的情况,单个锁也有可能出现死锁。

1、第一种常见的情况是加锁之后没有解锁。有可能是lock之后真的忘了unlock,这种比较少见也容易发现。但是有时候程序并不是跟我们预想的一样一帆风顺的走完流程,可能是在lock和unlock之间的代码出现了异常退出,这样就造成了加锁之后没有解锁,后续程序对该锁的请求无法实现,导致死锁等待。

解决方法:在c++语言中,就是利用所谓的Autolock局部对象,在该对象的构造函数中lock,在析构函数中unlock,因为是在栈中创建的对象,系统会自动执行析构函数,即使程序异常退出也会执行析构函数从而释放资源。

2、第二种是同一个线程中对同一个资源多次调用lock函数。有的互斥锁对象没有线程所有权属性,比如windows下的信号量Semaphores ,即一个线程获得某个信号量后,在他释放该信号量之前,他不能再次进入信号量保护的区域。如果信号量的计数只有1,同一个线程调用WaitForSingleObject两次,程序就会阻塞在第二次调用处造成死锁。

3、第三种情况就是我们通常所说的情况。有两个线程,线程1和线程2,有两个锁A和B,线程1持有A然后等待B,与此同时线程1持有B然后等待A。两个线程都不释放拥有的锁,也都获取不到等待的锁。

避免死锁一般针对的是第三种情况。

1、尽量不在同一个线程中同时锁住两个临界资源,不过如果业务要求必须这样,那就没办法。

2、有一种可行的办法是,多个线程对多个锁的加锁顺序一样,这样就不会发生死锁,比如线程1先对A资源加锁,再对B资源加锁,线程2也使用相同的顺序,就不会产生死锁。

3、还有一种可行的方案是一次性获取所有需要获取的锁,如果不能一次性获取则等待。我想了一下linux下可以用pthread_mutex_trylock函数来实现,伪代码如下(针对两个锁而言):

while (true)
{
    pthread_mutex_lock(&mutexA);
    if (0 == pthread_mutex_trylock(&mutexB))
    {
        //成功获取所有锁
        break;
     }
    else
    {
        //释放持有的锁,继续等待
        pthread_mutex_unlock(&mutexA);
        //延时一段时间再继续请求
        usleep(10*1000);
    }

}

//业务代码
...
pthread_mutex_unlock(&mutexA);
pthread_mutex_unlock(&mutexB);

4、还有一种方法是使用等待超时机制,如果等待一个锁太久没得到,就释放自己拥有的所有锁,避免死锁。这个方法感觉指标不治本,是处理死锁发生后的情况而不是有效的预防死锁。

5、听说还有一种是死锁检测机制。mysql数据库就具备死锁检测机制,死锁检测的算法目前没有研究过,感兴趣的同学可以自行研究。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 很高兴为您解答,Java多线程避免死锁方法有:1. 加锁次序:要求每个线程获取锁的顺序都是一致的;2. 加限制条件:在获取多个锁时,加入限制条件,如果不满足条件则不能获取锁;3. 使用可重入锁:可重入锁可以保证线程获取锁的次数不会超出一定的数量;4. 加锁超时:当线程获取锁超过一定的时间,则可以判断是否发生死锁,如果发生死锁,就可以放弃获取锁的操作。 ### 回答2: Java多线程编程中,死锁是一种常见的问题,发生死锁时,两个或多个线程互相等待对方释放资源,导致程序无法继续执行下去。为了避免死锁的发生,可以采取以下几种方法: 1. 避免嵌套锁:多线程编程中,尽量避免嵌套锁的使用。当一个线程获取了一个锁之后,尽量不要再去获取其他锁,尽量使锁的使用保持简单和单一化。 2. 保持锁的顺序一致:如果必须使用多个锁,确保在获取多个锁的时候,按照相同的顺序获取。这样可以避免不同线程获取锁的顺序不一致导致的死锁问题。 3. 使用定时锁:在使用锁时,可以使用带有超时机制的锁,即尝试获取锁一段时间后如果未能成功则放弃锁的获取,以避免因为某个线程无法成功获取锁而导致的死锁问题。 4. 使用资源分级策略:根据资源的重要性和访问频率,将资源进行分级,然后按照分级的顺序获取锁,这样可以避免低优先级的线程获取高优先级线程已经占有的锁。 5. 合理设计线程间的依赖关系:在多线程编程中,线程之间存在依赖关系是不可避免的。合理地设计线程间的依赖关系,并使用信号量、条件变量等方法来保证线程按正确的顺序执行,可以降低死锁的发生。 总结起来,避免死锁的关键在于合理使用锁和合理设计线程间的依赖关系。避免嵌套锁、保持锁的顺序一致、使用定时锁、资源分级策略和合理设计线程间的依赖关系等方法都可以有效地避免死锁的发生。 ### 回答3: Java多线程中如何避免死锁 死锁是指两个或多个线程彼此等待对方释放资源而无法继续执行的情况。为了避免死锁,可以采取以下几种措施: 1. 避免使用多个锁:尽量降低线程间的依赖,减少使用多个锁的情况,避免死锁的可能性。 2. 统一获取锁的顺序:通过约定,确保所有线程获取锁的顺序是一致的,这样可以避免因为锁的顺序不同而引发死锁。 3. 加锁时限:在获取锁的时候可以设置一个时间限制,超过一定时间未能成功获取锁,则放弃获取锁,防止因为无限等待而引发死锁。 4. 死锁检测与处理:可以通过使用工具对程序进行分析,检测潜在的死锁情况,并采取一定的措施来解除死锁。 5. 使用线程池:使用线程池可以有效地管理线程,避免因为线程数量过多而导致的资源竞争和死锁。 6. 少用嵌套锁:嵌套锁是指在一个锁的代码块中再次获取另一个锁,这样容易引发死锁,应尽量避免嵌套锁的使用。 7. 及时释放资源:尽量减少锁的持有时间,一旦不需要锁了就及时释放,避免因为持有锁时间过长而导致其他线程无法获取资源。 总之,为了避免死锁,要注意线程之间的调度和资源的竞争,并采取相应的措施来确保合理的资源使用和避免死锁的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值