[CareerCup] 16.4 A Lock Without Deadlocks 无死锁的锁

简介:

16.4 Design a class which provides a lock only if there are no possible deadlocks. 

有很多方法可以避免死锁的发生,一个常用的方法是列出所需要的锁,然后判断锁上这些锁后会不会发生死锁,比如有如下的锁的顺序:

A = {1, 2, 3, 4}

B = {1, 3, 5}

C = {7, 5, 9, 2}

这是有可能产生死锁的,比如当A锁上2等待3,当B锁上3等待5,当C锁上5等待2,我们可以将其看做图,2连上3,3连上5,5连上2,那么就会有环。一条边(w,v)表示锁上v后马上锁w,那么上述里子的图中的边为(1, 2), (2, 3), (3, 4), (1, 3), (3, 5), (7, 5), (5, 9), (9, 2)。那么我们在检测是否有死锁的情况就是要找图中是否存在环,我们可以用DFS来搜索所有的相连的部分,我们用DFS需要标记点的状态,我们首先定义个LockFactory类,用来保存锁的序列,比如上面的A,B,C,然后对于每一个锁序列,我们先将所有的锁都链起来,然后标记为false,然后用DFS判断是否有环,如果有环,则断开当前锁序列之间的所有连接,参见代码如下;

import java.util.Hashtable;
import java.util.LinkedList;
import java.util.concurrent.locks.Lock;

public class LockFactory {
    private static LockFactory instance;
    private int numberOfLocks = 5;
    private LockNode[] locks;
    private Hashtable<Integer, LinkedList<LockNode>> lockOrder;
private LockFactory(int count) {
        numberOfLocks = count;
        locks = new LockNode[numberOfLocks];
        lockOrder = new Hashtable<Integer, LinkedList<LockNode>>();
        for (int i = 0; i < numberOfLocks; ++i) {
            locks[i] = new LockNode(i, count);
        }
    }
public static LockFactory getInstance() {
        return instance;
    }
public static LockFactory initialize(int count) {
        if (instance == null) {
            instance = new LockFactory(count);
        }
        return instance;
    }
public boolean hasCycle(Hashtable<Integer, Boolean> touchedNodes, int[] resourcesInOrder) {
        for (int resource : resourcesInOrder) {
            if (touchedNodes.get(resource) == false) {
                LockNode n = locks[resource];
                if (n.hasCycle(touchedNodes)) {
                    return true;
                }
            }
        }
        return false;
    }
public boolean declare(int ownerId, int[] resourcesInOrder) {
        Hashtable<Integer, Boolean> touchedNodes = new Hashtable<Integer, Boolean>();
        int index = 1;
        touchedNodes.put(resourcesInOrder[0], false);
        for (index = 1; index < resourcesInOrder.length; ++index) {
            LockNode pre = locks[resourcesInOrder[index - 1]];
            LockNode cur = locks[resourcesInOrder[index]];
            pre.joinTo(cur);
            touchedNodes.put(resourcesInOrder[index], false);
        }
        if (hasCycle(touchedNodes, resourcesInOrder)) {
            for (int j = 1; j < resourcesInOrder.length; ++j) {
                LockNode p = locks[resourcesInOrder[j - 1]];
                LockNode c = locks[resourcesInOrder[j]];
                p.remove(c);
            }
            return false;
        }
        LinkedList<LockNode> list = new LinkedList<LockNode>();
        for (int i = 0; i < resourcesInOrder.length; ++i) {
            LockNode resource = locks[resourcesInOrder[i]];
            list.add(resource);
        }
        lockOrder.put(ownerId, list);
        return true;
    }
public Lock getLock(int ownerId, int resourceId) {
        LinkedList<LockNode> list = lockOrder.get(ownerId);
        if (list == null) return null;
        LockNode head = list.getFirst();
        if (head.getId() == resourceId) {
            list.removeFirst();
            return head.getLock();
        }
        return null;
    }
}

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockNode {
    public enum VisitState {
        FRESH, VISITING, VISITED
    };
    private ArrayList<LockNode> children;
    private int lockId;
    private Lock lock;
    private int maxLocks;
public LockNode(int id, int max) {
        lockId = id;
        children = new ArrayList<LockNode>();
        maxLocks = max;
    }
public void joinTo(LockNode node) {
        children.add(node);
    }
public void remove(LockNode node) {
        children.remove(node);
    }
public boolean hasCycle(Hashtable<Integer, Boolean> touchedNodes) {
        VisitState[] visited = new VisitState[maxLocks];
        for (int i = 0; i < maxLocks; ++i) {
            visited[i] = VisitState.FRESH;
        }
        return hasCycle(visited, touchedNodes);
    }
public boolean hasCycle(VisitState[] visited, Hashtable<Integer, Boolean> touchedNodes) {
        if (touchedNodes.containsKey(lockId)) {
            touchedNodes.put(lockId, true);
        }
        if (visited[lockId] == VisitState.VISITING) {
            return true;
        } else if (visited[lockId] == VisitState.FRESH) {
            visited[lockId] = VisitState.VISITING;
            for (LockNode n : children) {
                if (n.hasCycle(visited, touchedNodes)) {
                    return true;
                }
            }
            visited[lockId] = VisitState.VISITED;
        }
        return false;
    }
public Lock getLock() {
        if (lock == null) {
            lock = new ReentrantLock();
        }
        return lock;
    }
public int getId() {
        return lockId;
    }
}
public class j {
    public static void main(String[] args) {
        int[] res1 = {1, 2, 3, 4};
        int[] res2 = {1, 5, 4, 1};
        int[] res3 = {1, 4, 5};
        LockFactory.initialize(10);
        
        LockFactory lf = LockFactory.getInstance();
        System.out.println(lf.declare(1, res1));
        System.out.println(lf.declare(2, res2));
        System.out.println(lf.declare(3, res3));
        
        System.out.println(lf.getLock(1, 1));
        System.out.println(lf.getLock(1, 2));
        System.out.println(lf.getLock(1, 3));
        System.out.println(lf.getLock(1, 4));
        System.out.println(lf.getLock(2, 1));
        System.out.println(lf.getLock(2, 5));
        System.out.println(lf.getLock(2, 4));
        System.out.println(lf.getLock(3, 1));
        System.out.println(lf.getLock(3, 4));
        System.out.println(lf.getLock(3, 5));
    }
}

本文转自博客园Grandyang的博客,原文链接:无死锁的锁[CareerCup] 16.4 A Lock Without Deadlocks ,如需转载请自行联系原博主。

相关文章
|
存储 设计模式 缓存
通用点赞设计思路
点赞作为一个高频率的操作,如果每次操作都读写数据库会增加数据库的压力,所以采用缓存+定时任务来实现。点赞数据是在redis中缓存半小时,同时定时任务是每隔5分钟执行一次,做持久化存储,这里的缓存时间和任务执行时间可根据项目情况而定。
2963 2
|
机器学习/深度学习 人工智能 自然语言处理
扩散引导语言建模(DGLM):一种可控且高效的AI对齐方法
DGLM(Diffusion Guided Language Modeling)是一种新型框架,结合了自回归模型的流畅性和扩散模型的灵活性,解决了现有引导生成方法的局限性。DGLM通过扩散网络生成语义提案,并使用轻量级提示生成器将嵌入转化为软提示,引导自回归解码器生成文本。该方法无需微调模型权重,易于控制新属性,并在多个基准数据集上表现出色。实验结果显示,DGLM在毒性缓解、情感控制和组合控制等方面优于现有方法,为可控文本生成提供了新的方向。
314 11
扩散引导语言建模(DGLM):一种可控且高效的AI对齐方法
|
前端开发 安全 API
前端全栈之路Deno篇(三):一次性搞懂和学会用Deno 2.0 的权限系统详解和多种权限配置权限声明方式
本文深入解析了 Deno 2.0 的权限系统,涵盖主包和第三方包的权限控制机制,探讨了通过命令行参数、权限 API 和配置文件等多种权限授予方式,并提供了代码示例和运行指导,帮助开发者有效管理权限,提升应用安全性。
352 0
|
缓存 JavaScript 数据安全/隐私保护
Vue学习之--------路由守卫(2022/9/6)
这篇文章详细介绍了Vue路由守卫的概念和应用,包括全局守卫、独享守卫和组件内守卫的实现方法,并通过实际代码示例和测试效果展示了如何对路由进行权限控制,以及Vue路由器的两种工作模式:hash模式和history模式。
Vue学习之--------路由守卫(2022/9/6)
|
Kubernetes JavaScript API
如何理解 Istio Ingress, 它与 API Gateway 有什么区别?东西流量?南北流量?
这三者都和流量治理密切相关,那么流量治理在过去和现在有什么区别呢?都是如何做的呢? 在学习istio的时候对流量管理加深了理解。什么是东西流量?什么是南北流量?
644 0
|
vr&ar Android开发 iOS开发
移动应用与系统:探索开发与创新的前沿
本文深入探讨了移动应用开发和操作系统的关键要素,包括技术选择、用户体验设计、市场趋势、安全性问题以及未来发展方向。通过对移动应用生态系统的全面分析,旨在为读者提供清晰的行业洞察和实践指导。
|
域名解析 缓存 网络协议
阿里云DNS常见问题之新买的域名生效很慢如何解决
阿里云DNS(Domain Name System)服务是一个高可用和可扩展的云端DNS服务,用于将域名转换为IP地址,从而让用户能够通过域名访问云端资源。以下是一些关于阿里云DNS服务的常见问题合集:
|
BI API 流计算
[实时流基础 flink] 窗口
[实时流基础 flink] 窗口
295 1
|
XML JSON 网络协议
《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(7)-Fiddler状态面板-QuickExec命令行
【2月更文挑战第8天】《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(7)-Fiddler状态面板-QuickExec命令行
179 5
|
人工智能 分布式计算 安全
【现代密码学】笔记1.2 -- 对称密钥加密、现代密码学的基本原则《introduction to modern cryphtography》现代密码学原理与协议
【现代密码学】笔记1.2 -- 对称密钥加密、现代密码学的基本原则《introduction to modern cryphtography》现代密码学原理与协议
973 0