zoukankan      html  css  js  c++  java
  • 【JAVA并发编程实战】8、锁顺序死锁

    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();
        }
    }

    测试结果:

  • 相关阅读:
    绕口令系列 1
    毕业论文排版
    使用matlab表示“段数不确定”的分段函数
    [转]C/C++关于全局变量和局部变量初始化与不初始化的区别
    [转]基于Protel DXP软件的PCB高级编辑技巧大全
    冒泡排序及其优化
    gcc编译器参数
    [转]跟我一起写Makefile系列
    实例说明optimize table在优化mysql时很重要
    log4php0.9的详细配备实例说明
  • 原文地址:https://www.cnblogs.com/cutter-point/p/6072912.html
Copyright © 2011-2022 走看看