• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

张秋天

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

并发代码-死锁

 

死锁原因

两个或多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,都等待对方释放资源,如果都不主动释放,产生死锁。

 互斥:资源具有排它性,只能被一个进程占用,直到被该进程释放

 请求和保持条件:一个进程请求其他资源发生阻塞时,已获得的资源保持不放。

 不剥夺条件:资源在没被进程释放前,其他进程无法对他剥夺占用

 循环等待条件:等待的进程形成一个环路(死循环),造成永久阻塞。

 

死锁代码

public class DeadLock {

    private static Object locka = new Object();
    private static Object lockb = new Object();

    public void deadLock(){
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                
                synchronized (locka){  // 获取A锁
                    System.out.println(Thread.currentThread().getName() + "get locka");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    System.out.println("need lockb"); // 获取B锁
                    synchronized (lockb){
                        System.out.println(Thread.currentThread().getName() + "get lockb");
                    }
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockb){  // 获取B锁
                    System.out.println(Thread.currentThread().getName() + "get lockb");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("need locka");
                    synchronized(locka){ // 获取A锁
                        System.out.println(Thread.currentThread().getName() + "get locka");
                    }
                }
            }
        });

        thread1.start();
        thread2.start();
    }
    
    
    public static void main(String[] args) {
        new DeadLock().deadLock();
    }
}

避免死锁 

产生死锁的四个必要条件:互斥条件、持有并等待条件、不可剥夺条件、环路等待条件。避免死锁问题就只需要破环其中一个条件就可以

 

加锁顺序 所有的线程,按照相同的顺序获得锁

加锁时限 尝试获取锁的时候加一个超时时间,一个线程没有在给定时限内成功获取锁,进行回退、释放所有已经获得的锁,然后等待一段随机的时间再重试。

死锁检测 当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。

 一个可行的做法:释放所有锁,回退,并且等待一段随机的时间后重试

 一个更好的方案:线程设置优先级,让一个(或几个)线程回退。

 

最常见的并且可行的就是使用资源有序分配法,来破环环路等待条件。

线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 是先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。线程 A 和 线程 B 总是以相同的顺序申请自己想要的资源。

 

操作系统-银行家算法

 保证系统动态分配资源后,不会进入不安全状态,避免可能产生的死锁。

 

当进程提出资源请求,资源能够满足该请求,判断满足请求后系统状态是否安全

  • 如果安全,给该进程分配资源
  • 否则不分配资源,申请资源的进程将阻塞。

 

鸵鸟策略

解决死锁的 代价很高,不采取任何措施,能获得更高的性能。

死锁发生 概率很低,就算发生死锁对对用户的影响并不大,所以可以采用鸵鸟策略。

大多数操作系统,Linux、Unix、Windows,解决死锁的办法是忽略它。

 

 

 

 

 

 

 

posted on 2021-01-20 12:36  张秋天  阅读(147)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3