java並發編程如何預防死鎖


  在java並發編程領域已經有技術大咖總結出了發生死鎖的條件,只有四個條件都發生時才會出現死鎖:

 1.互斥,共享資源X和Y只能被一個線程占用

 2.占有且等待,線程T1已經取得共享資源X,在等待共享資源Y的時候,不釋放共享資源X

 3.不可搶占,其他線程不能強行搶占線程T1占有的資源

 4.循環等待,線程T1等待線程T2占有的資源,線程T2等待線程T1占有的資源,就是循環等待

  只要能破壞其中一個,就可以成功避免死鎖的發生,因為對於共享資源我們要得就是互斥的效果,所以第一個條件是無法破壞的,所以可以從下面三個條件出手,具體實現方式:

 1.對於“占用且等待”這個條件,我們可以一次性申請所有的資源,這樣就不存在等待了

  

class Allocator{
        //通過破壞占有且等待條件避免死鎖現象的發生
        private List<Object> als = new ArrayList<>();
        //一次申請所有的資源
        synchronized boolean apply(Object from, Object to){
            if (als.contains(from) || als.contains(to)){
                //只要存在一個賬戶被其他的業務鎖定則無法完成轉賬業務
                return false;
            }else {
                als.add(from);
                als.add(to);
            }
            return true;
        }
        //歸還資源
        synchronized void free(Object from,Object to){
            als.remove(from);
            als.remove(to);
        }
    }
    class Account {
        //actr應該為單例
        private Allocator actr;
        private int balance;
        //轉賬
        void  transfer(Account target, int amt){
            //一次性申請轉出和轉入賬戶,直到成功
            while (!actr.apply(this,target));
            try{
                //鎖定轉出賬戶
                synchronized (this){
                    //鎖定轉入賬戶
                    synchronized (target){
                        if (this.balance > amt){
                            this.balance -= amt;
                            target.balance += amt;
                        }
                    }
                }
            }finally {
                actr.free(this, target);
            }
        }
    }

 

 2.對於“不可搶占”這個條件,占用部分資源的線程進一步申請其他資源時,如果申請不到,可以主動釋放它所占有的資源,這樣不可搶占這個條件就破壞掉了

 3.對於“循環等待”這個條件,可以靠按序申請資源來預防,所謂按序申請,是指資源是有線性順序的,申請的時候可以先申請資源序號小的,再申請資源序號大的,這樣線性化后自然就不存在循環了

    class Accounts{
        private int id;
        private int balance;
        //轉賬
        void  transfer(Accounts target,int amt){
            Accounts left = this;
            Accounts right = target;
            if (this.id > target.id){
                left = target;
                right = this;
            }
            //鎖定序號小的賬戶
            synchronized (left){
                //鎖定序號大的賬戶
                synchronized (right){
                    if (this.balance > amt){
                        this.balance -= amt;
                        target.balance += amt;
                    }
                }
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM