synchronizedはフェアロックか非フェアロックか

2159 ワード

どんなに推測しても、直接ケースを書いて、検証して、直接コードをつけたほうがいいです.
public class TestSynchronized {

    public volatile boolean flag;//            
    
    //   5  ,            
    public synchronized void blockWhile(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    //      ,     
    public synchronized void blockMethod(){
        if (!this.flag){this.flag = true;}
        System.out.println("block Method : " + System.currentTimeMillis());
    }
    
    //      
    public synchronized void newMethod(){
        System.out.println("new Method : " + System.currentTimeMillis());
    }
    
    public static void main(String[] args) throws InterruptedException {
        TestSynchronized testSynchronized = new TestSynchronized();
        
        Thread a = new Thread(testSynchronized::blockWhile);
        
        a.start();
        Thread.sleep(10);//  a     
        
        Thread b = new Thread(() -> {
          for (int i = 0; i < 50;i++){
              testSynchronized.blockMethod();
          } 
        });
        
        b.start();//b    50     
        System.out.println("finish block Method : " + System.currentTimeMillis());
        Thread c = new Thread(() -> {
            int i = 0;
            while (true){
                if (testSynchronized.flag){
                    for ( ; i < 50;i++){
                        testSynchronized.newMethod();
                    }
                }
            }
        });
        c.start();//c   b          ,         ,                    
    }
}

実行結果は以下のようになり、実行結果にはランダム性が強く、実行数を増やしたり、メソッドの実行回数を増やしたりして、次のような結果が得られます.
finish block Method : 1591683424652
block Method : 1591683429643
block Method : 1591683429643
block Method : 1591683429643
block Method : 1591683429643
new Method : 1591683429643
new Method : 1591683429643
block Method : 1591683429643
block Method : 1591683429643
block Method : 1591683429643
......

説明、synchronizedは非公平ロックであり、スレッドの起動段階の時間を無駄にせず、新しい呼び出しを実行する方法であり、スループットを増加させ、欠点は飢餓ロックをもたらす可能性がある.