0

0

【JAVA并发编程实战】锁顺序死锁

高洛峰

高洛峰

发布时间:2016-11-17 13:39:15

|

2058人浏览过

|

来源于php中文网

原创

package cn.study.concurrency.ch10;

public class Account {
    private String staffAccount;    //账号
    private String passWord;    //密码
    private int balance; //账户余额
    
    public Account(int money) {
        this.balance = money;
    }
    
    public String getStaffAccount() {
        return staffAccount;
    }
    public void setStaffAccount(String staffAccount) {
        this.staffAccount = staffAccount;
    }
    public String getPassWord() {
        return passWord;
    }
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
    
    public void debit(int amount)
    {
        System.out.println("转出账户:" + amount);
    }
    
    public void credit(int amount)
    {
        System.out.println("转入账户:" + amount);
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }
    
}
package cn.study.concurrency.ch10;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.naming.InsufficientResourcesException;

/**
 * 通过制定确定的锁顺序来避免死锁
 * @author xiaof
 *
 */
public class DeathLock {
    public void transferMoney(Account fromAccount, Account toAccount, int amount) throws InsufficientResourcesException
    {
        synchronized(fromAccount)
        {
            synchronized(toAccount)
            {
                //按参数的顺序上锁,这个依据参数的调用方法的顺序
                if(fromAccount.getBalance() < amount)
                {
                    //账户余额不足,无法转账
                    throw new InsufficientResourcesException();
                }
                else
                {
                    fromAccount.debit(amount);
                    toAccount.credit(amount);
                }
            }
        }
    }
    /**
     * 这个用来在无法判定枷锁顺序的时候的加时赛锁
     */
    private static final Object tieLock = new Object();
    
    public static void transferMoney2(final Account fromAccount, final Account toAccount, final int amount) throws InsufficientResourcesException
    {
        /**
         * 辅助内部类
         * @author xiaof
         *
         */
        class Helper
        {
            public void transfer() throws InsufficientResourcesException
            {
                //内部类可以随意访问外部类成员
                //按参数的顺序上锁,这个依据参数的调用方法的顺序
                if(fromAccount.getBalance() < amount)
                {
                    //账户余额不足,无法转账
                    throw new InsufficientResourcesException();
                }
                else
                {
                    fromAccount.debit(amount);
                    toAccount.credit(amount);
                }
            }
        }
        //返回给定对象的哈希码,该代码与默认的方法 hashCode() 返回的代码一样,无论给定对象的类是否重写 hashCode()
        int fromHash = System.identityHashCode(fromAccount);
        int toHash = System.identityHashCode(toAccount);
        //根据hash值判定加锁顺序,那么一样的对象的锁顺序就一定一样
        if(fromHash < toHash)
        {
            synchronized(fromAccount)
            {
                synchronized(toAccount)
                {
                    new Helper().transfer();
                }
            }
        }
        else if(toHash < fromHash)
        {
            synchronized(toAccount)
            {
                synchronized(fromAccount)
                {
                    new Helper().transfer();
                }
            }
        }
        else
        {
            //如果很不巧,hash值是一样的,那么就需要一个加时赛的机制,先获取外部锁,然后再此基础上对两个对象随机上锁
            synchronized(tieLock)
            {
                synchronized(fromAccount)
                {
                    synchronized(toAccount)
                    {
                        new Helper().transfer();
                    }
                }
            }
        }
        
    }
    
    static Account account1 = new Account(999);
    static Account account2 = new Account(999);
    
    public static void main(String[] args) throws InsufficientResourcesException {
        //对于第一个方法很容易死锁
        //比如:当有两个同时执行这个方法的调用时候
//        DeathLock dl = new DeathLock();
        //这个时候第一个调用在锁了account1,然后第二个调用锁了account2
        //同时第一个需要account2,第二个需要account1,这就发生竞争死锁了
//        dl.transferMoney(account1, account2, 998);
//        dl.transferMoney(account2, account1, 998);
//        
//        dl.transferMoney2(account1, account2, 998);
        ExecutorService pool = Executors.newFixedThreadPool(10);
        for(int i = 0; i < 5; ++ i)
        {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        DeathLock.transferMoney2(account1, account2, 998);
                    } catch (InsufficientResourcesException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        
        for(int i = 0; i < 5; ++ i)
        {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        DeathLock.transferMoney2(account2, account1, 998);
                    } catch (InsufficientResourcesException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        
        pool.shutdown();
    }
}

测试结果:

QQ图片20161117104700.png

Reclaim.ai
Reclaim.ai

为优先事项创建完美的时间表

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

28

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

20

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

11

2026.01.22

PHP特殊符号教程合集
PHP特殊符号教程合集

本专题整合了PHP特殊符号相关处理方法,阅读专题下面的文章了解更多详细内容。

11

2026.01.22

PHP探针相关教程合集
PHP探针相关教程合集

本专题整合了PHP探针相关教程,阅读专题下面的文章了解更多详细内容。

8

2026.01.22

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

52

2026.01.22

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.8万人学习

C# 教程
C# 教程

共94课时 | 7.4万人学习

Java 教程
Java 教程

共578课时 | 49.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号