JAVA并发编程学习笔记------锁顺序死锁
一、需求描述:
将资金从一个账户转移到另一个账户。
二、程序实现:
(1)账户类:
public class Account {
    private long account;
    public Account(String user, long account) {
        this.account = account;
    }
    public Account() {
        super();
    }
    public long getAccount() {
        return account;
    }
    public void setAccount(long account) {
        this.account = account;
    }
    public void debit(long money){
        this.account -= money;
    }
    public void credit(long money){
        this.account += money;
    }
}
(2)资产转移类:
public class TransMoney {
    private static final Object tieLock = new Object();
    public static void transferMoney(Account fromAccount,Account toAccount,long amount){
        synchronized (fromAccount){
            synchronized (toAccount){
                fromAccount.debit(amount);
                toAccount.credit(amount);
            }
        }
    }
}
(3)测试类:
public class DemonstrateDeadLock {
    private static final int NUM_THREADS = 20;
    private static final int NUM_ACCOUNTS = 5;
    private static final int NUM_ITERATIONS = 1000000;
    public static void main(String[] args) {
        final Random rdn = new Random();
        final Account[] accounts = new Account[NUM_ACCOUNTS];
        for(int i=0;i<accounts.length;i++){
            accounts[i] = new Account();
        }
        class TransferThread extends Thread{
            public void run(){
                for(int i=0;i<NUM_ITERATIONS;i++){
                    int fromAccount = rdn.nextInt(NUM_ACCOUNTS);
                    int toAccount = rdn.nextInt(NUM_ACCOUNTS);
                    TransMoney.transferMoney(accounts[fromAccount],accounts[toAccount],rdn.nextInt(1000));
                }
            }
        }
        for(int i=0;i<NUM_THREADS;i++){
            new TransferThread().start();
        }
    }
}
(4)解析:
上述程序容易形成死锁,原因在于多账户调用TransMoney.transferMoney时,存在锁顺序冲突,
解决方案是使用System.identityHashCode来定义锁的顺序,消除死锁的可能性,代码实现如下:
public static void transferMoney(final Account fromAccount,final Account toAccount,final long amount){
    class Helper{
        public void transfer(){
            fromAccount.debit(amount);
            toAccount.credit(amount);
        }
    }
    int fromHash = System.identityHashCode(fromAccount);
    int toHash = System.identityHashCode(toAccount);
    if(fromHash < toHash){
        synchronized (fromAccount){
            synchronized (toAccount){
                new Helper().transfer();
            }
        }
    }else if(fromHash > toHash){
        synchronized (toAccount){
            synchronized (fromAccount){
                new Helper().transfer();
            }
        }
    }else{
        synchronized (tieLock){
            synchronized (fromAccount){
                synchronized (toAccount){
                    new Helper().transfer();
                }
            }
        }
    }
}
JAVA并发编程学习笔记------锁顺序死锁的更多相关文章
- Java并发编程学习笔记
		Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ... 
- Java 并发编程学习笔记 理解CLH队列锁算法
		CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁.结点之间是通过隐形的链表相连,之所以叫隐形的链 ... 
- Java并发编程学习笔记 深入理解volatile关键字的作用
		引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ... 
- JAVA并发编程学习笔记------协作对象之间发生的死锁
		一. 如果在持有锁时调用某个外部方法,那么将出现活跃性问题.在这个外部方法中可能会获取其他锁(这可能会产生死锁),或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁.如下代码: public c ... 
- JAVA并发编程学习笔记------多线程调优
		1. 多线程场景下尽量使用并发容器代替同步容器 (如ConcurrentHashMap代替同步且基于散列的Map, 遍历操作为主要操作的情况下用CopyOnWriteArrayList代替同步的Lis ... 
- Java并发编程学习笔记(一)——线程安全性
		主要概念:线程安全性.原子性.原子变量.原子操作.竟态条件.复合操作.加锁机制.重入.活跃性与性能. 1.当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变 ... 
- JAVA并发编程学习笔记之ReentrantLock
		ReentrantLock是一个可重入的互斥锁,ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁.如果锁已经被当前线程拥有, ... 
- Java并发编程学习笔记(二)——对象的共享
		主要概念:可见性.重排序.失效数据.最低安全性.发布.逸出.线程封闭(Ad-hoc.栈封闭.ThreadLocal类).不变性.Final域.事实不可变对象. 1.在没有同步的情况下,编译器.处理器以 ... 
- java并发编程学习笔记(一)初识并发原子性
		1.并发的意义 现在是一个多核的时代,并发的存在意义就是为了能够充分利用多核计算机的优势,提高程序的运行效率: 2.并发的风险 竞争-----多个线程对内存数据数据进行读写操作时,对数据处理结果的一个 ... 
随机推荐
- 13、ABPZero系列教程之拼多多卖家工具 微信公众号开发前的准备
			因为是开发阶段,我需要在本地调试,而微信开发需要配置域名,这样natapp.cn就有了用武之地,应该说natapp就是为此而生的. natapp.cn是什么 这是一个内网映射的网站,支持微信公众号.小 ... 
- python递归查找文件目录
			# -*- coding:utf-8 -*- import os allfile = []def get_all_file(path): allfilelist = os.listdir(path) ... 
- AtCoder Regular Contest 075
			任意门 C - Bugged 题意:类似装箱问题,但是最后体积总和不能为10的倍数. #include<cstdio> #include<cstring> #include&l ... 
- HDU 5752 Sqrt Bo【枚举,大水题】
			Sqrt Bo Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total S ... 
- [51nod1610]路径计数
			路径上所有边权的最大公约数定义为一条路径的值. 给定一个有向无环图. T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模). Inp ... 
- B. Gerald is into Art
			B. Gerald is into Art time limit per test 2 seconds memory limit per test 256 megabytes input standa ... 
- 教你如何解决Sublime Text 3使用中出现的中文乱码问题
			Sublime Text 3 是一个非常不错的源代码及文本编辑器,但是不支持GB2312和GBK编码在很多情况下会非常麻烦. 不过Sublime Package Control所提供的插件可以让Sub ... 
- 布隆(Bloom)过滤器 JAVA实现
			前言 Bloom过滤器,通过将字符串映射为信息指纹从而节省了空间.Bloom过滤器的原理为,将一个字符串通过一定算法映射为八个Hash值,将八个Hash值对应位置的Bitset位进行填充.在进行校验的 ... 
- [C#]使用控制台获取天气预报
			本例子主要是使用由中央气象局网站(http://www.nmc.gov.cn)提供的JSON API,其实现思路如下: 1.访问获取省份(包含直辖市.自治区等,以下简称省份)的网址(http://ww ... 
- insertBefore方法(javascript与jQuery)
			说到insertBefore()方法,其实javascript与jQuery中都有此方法,那么他们用法是否相同呢? 其实,还是有点区别的.反正我是爱搞混淆了,先做个小笔记吧! 1.insertBefo ... 
