Synchronizedの詳細

5275 ワード

synchronizedキーワードは、Java内のマルチスレッドが同じリソースにアクセスする際に発生するリソース競合の問題を、コードブロック/メソッドボディにロックすることで解決します.
synchronized同期ロックは2つのタイプに分けられ、4つの表現形式があります.
  • オブジェクトロック:1つのインスタンスオブジェクトのプライベートメモリの一部の領域をロックします.
  • 非静的修飾方法
  • 修飾コードブロック
  • クラスロック:クラス全体の共有メモリの一部領域にロックをかける
  • 静的修飾方法
  • 修飾コードブロック
  • Find Two Object
    ウォーズギソド:オブジェクト向けプログラミングの真髄は、実際にフィットし、理解しやすいオブジェクトモデルを構築しやすいことです.たとえば、設計モードがオブジェクト向けのプログラミングに使用されるのは明らかに理解しやすい.:)
  • まずHumanクラスを定義します:
  • public class Human {
        //   Human         
        public void eatDinner() {
            pickupByLeftHand(); //       
            eatFoodByMouth(); //     
        };
        //   Human        
        public void drinkWater() {
            pickupByRightHand(); //      
            drinkWaterByMouth();   //    
        } 
        //   
        public void watchTV() {
        }
    }
    
  • 次に、2つのオブジェクトをインスタンス化します.
  • Human XiaoMing = new Human();  //  
    Human XiaoMingTaBa = new Human();  //    
    
    Let's have dinner!
    明ちゃんは晩ご飯を食べます.XiaoMing.eatDinner()、急に水を飲みたくなりました.彼は口が1つしかないのに、水を飲んだりご飯を食べたりするとむせてしまうでしょう.この時私たちは解決策を考えました.
    //   synchronized       eatDinner() 
    public synchronized void eatDinner() {
        pickupByHand(); //      
        eatFoodByMouth(); //     
    }
    //   synchronized       drinkWater
    public synchronized void eatDinner() {
        pickupByHand(); //     
        drinkWaterByMouth();   //    
    }
    
    今、明ちゃんが食事をしている間に、彼は水を飲みたいと思っていました.私たちはsynchronizedを使ってこの2つの動作を修飾したからです.明ちゃんは水を飲む前にご飯を食べてから水を飲む動作をします.これで衝突の問題が解決した.さらにwatchTV()という動作を分析します.この動作は夕食を食べて水を飲むのと衝突していないので、synchronizedキーワードを修飾する必要はありません.
    synchronized修飾の非静的メソッドを呼び出すと、synchronized修飾を採用した同期メソッドはすべてロックされ、synchronized修飾を採用していない非同期メソッドはすべて実行できます.
    今、明ちゃんのお父さんが食事をして水を飲む問題を検討してみましょう.明ちゃんのeatDinner()方法とdrinkWater()方法を同期ロックしましたが、明らかなのは.明ちゃんが水を飲んでご飯を食べる動作は明ちゃんのお父さんが水を飲んでご飯を食べる動作に影響しません.上記の結論を改善することができます
    Conclusion 1:synchronizedを使用して非静的メソッドを修飾インスタンスオブジェクトA(XiaoMing)を介して非静的同期メソッド(eat or drink)にアクセスすると、オブジェクトAを介して非静的同期メソッド(eat or drink)にアクセスするすべての操作は、別の操作が実行されるまでブロックされ、オブジェクトAを介して非静的同期メソッドにアクセスするすべての操作(watchTV)はブロックされます.まだ実行できます.一方、オブジェクトAを介して同期メソッドにアクセスする場合、オブジェクトBを介して任意の同期メソッドにアクセスすることができる.(つまり、明ちゃんがご飯を食べて水を飲むのは、明ちゃんのお父さんがご飯を食べて水を飲むのに影響しません)
    Let's have dinnerもう一度!
    もう一つの食事と水の状況を分析しましょう.明ちゃんと明ちゃんのお父さんは一緒に食事をしていて、二人とも水を飲みたいと思っていましたが、机の上には水が1本しかありませんでした.この水は二人で先に手に入れた人が誰でも飲めます.明ちゃんの経験では、食事をしながら水を飲むとむせてしまうので、ご飯を食べてから水を飲むしかないと教えてくれました.明ちゃんのお父さんが食べた塩は明ちゃんが食べた米よりも多く、経験豊富な彼は食事中に水を飲むとむせてしまうのは口が1つしかないからだと知っていますが、私たちは両手を持っています.だから彼の食事と水を飲む動作はこのように実現しました.
    public void eatDinner() {
        pickupByLeftHand(); //      
        synchronized (mouth) {
            eatFoodByMouth(); //     
        }
    };
    public void drinkWater() {
        pickupByRightHand(); //     
        synchronized (mouth) {
            drinkWaterByMouth();   //    
        }
    }
    
    
    だから彼は食事をしながら、手で水を取った.はい、明ちゃんと明ちゃんのお父さんは食事のスピードがあまり悪くありませんが、みんながご飯を食べ終わったとき、水はもう明ちゃんのお父さんの手にありました...(明ちゃん呆然と.jpg)総食事時間計時はこうです:(競争関係がなければ)明ちゃん:timeOf(右手で食べ物を取る)+timeOf(口で食べ物を食べる)+timeOf(左手で水を取る)+timeOf(水を飲む)明ちゃんお父さん:imeOf(右手で食べ物を取る)+timeOf(口で食べ物を食べると同時に左手で水を取ることができ、食べ物を食べる時間を増やすことはできません)+timeOf(水を飲む)だからまた一つの結論を得た
    **Conclusion 2:**オブジェクトロックの2つの形式の違いこの2つの形式には本質的な違いはありません.違いは、コードブロックを修飾する形式ができるだけロックする必要がある同期コードを簡素化し、私たちのシステムが高同時性で、資源競争が激しい場合により効率的になることです.
    クラスロックについて
    まあ、類比の例は思いつかない.直接結論を述べる.
    Conclusion 3:クラスロック(synchronizedが静的メソッドを修飾し、synchronized(Human.class)がコードブロックを修飾する操作にアクセスすると、synchronizedで修飾された他のすべての静的メソッドとsynchronized(Human.this)で修飾されたコードブロックがロックされます(静的非同期メソッドはロックされません).ただし、オブジェクトロックには影響しません.冒頭には、2つのロックがロックされているメモリ領域が異なることを説明します.
    Conclusion 4:クラスロックの2つの形式の違い参照オブジェクトロックの2つの形式の違い
    The Last Supper
    synchronizedの2つのタイプについて,4つの形式で以下の結論を得ることができる.
  • スレッドがAオブジェクトを介して非静的同期メソッド(または同期コードブロック)にアクセスすると、他のスレッドがAオブジェクトを介して非静的同期メソッド(または同期コードブロック)にアクセスする操作がロックされます.しかし、他のスレッドがAオブジェクトを介して非静的非同期メソッドにアクセスする操作はロックされず、Bオブジェクトを介して非静的同期メソッドにアクセスする操作もロックされない.(各オブジェクトのロックは独立しているのでオブジェクトロックと呼ぶ)
  • スレッドが静的同期メソッドまたはクラスロックによって修飾された同期コードブロックにアクセスすると、クラスの静的メソッドまたは同じクラスロックによって修飾された同期コードブロックはすべてロックされ、他のスレッドはアクセスできません.
  • クラスロックとオブジェクトロックは互いに影響しません.
  • 修飾方法は、修飾コードブロックと本質的に同じであり、違いは、修飾コードブロックの方式が競争が激しい場合により効率的であることにある.
  • 以下のコードを区別するオブジェクトロックの所持状況
  • に注意する.
    public class Human {
        //XiaoMing.eatDinner();
        public synchronized void eatDinner() {   //     XiaoMing
            pickupByLeftHand();
            eatFoodByMouth();
        };
        
        //XiaoMing.eatDinner2();
        public void eatDinner() {
            synchronized(this) {    //     XiaoMing
                pickupByLeftHand();
                eatFoodByMouth();
            }
        };
        
        //XiaoMing.drinkWater();
        public void drinkWater() {
            pickupByRightHand();
            synchronized (mouth) {  //     mouth
                drinkWaterByMouth();
            }
        }
    }
    
    付属:4種類のロック
  • オブジェクトロック:1つのインスタンスオブジェクトのプライベートメモリの一部の領域をロックします.
  • 非静的修飾方法
  • public synchronized void doSth() {}
    
  • 修飾コードブロック
  • public void doSth() {
          synchronized (obj) {
          }
    }
    
  • クラスロック:クラス全体の共有メモリの一部領域にロックをかける
  • 静的修飾方法
  • public static synchronized void doSth() {}
    
  • 修飾コードブロック
  • public void doSth() {
          synchronized (ClassA.class) {
          }
    }