JDK1.8 ConcurrentHashMap computeIfAbsentネストされたデッドロックバグ

10208 ワード

たまたまこのバグを見たので、メモしておきます

Bug情報

  • バージョンJDK 1.8(現在8 u 261までテストされているが、まだこの問題があるかどうかは不明である)、少なくとも1.9で
  • が修復されたことは間違いない.
  • シーンConcurrentHashMapにおけるcomputeIfAbsentの再ネストcomputeIfAbsent/putIfAbsent
  • 現象スレッドデッドロック
  • コード#コード#

    public class CHMTest {
        public static void main(String[] args) {
            normal();
            bug();
        }
        private static void bug(){
            System.out.println("begin bug code ...");
            Map<String, Integer> map = new ConcurrentHashMap<>(16);
            System.out.println(map.size());
            String hash1 = "AaAa";
            String hash2 = "BBBB";
            //hash , 
            System.out.println("hash1:"+hash1.hashCode()+",hash1:"+hash2.hashCode());
            map.computeIfAbsent(hash1, key -> {
                map.putIfAbsent(hash2,1);
                return 1;
            });
            System.out.println(map.size());
            System.out.println("bug code is exec here?");
        }
        private static  void normal(){
    
            System.out.println("begin normal code ...");
            Map<String, Integer> map = new ConcurrentHashMap<>(16);
            System.out.println(map.size());
            String hash1 = "AaAa";
            String hash2 = "BBBB2";
            System.out.println("hash1:"+hash1.hashCode()+",hash1:"+hash2.hashCode());
            map.computeIfAbsent(hash1, key -> {
                map.putIfAbsent(hash2,1);
                return 1;
            });
            System.out.println(map.size());
            System.out.println("begin normal code finished");
        }
    }
    

    上記のコードを実行すると、bugメソッドブロックがデッドロックします.computeIfAbsentにcomputeIfAbsentまたはputIfAbsentをネストすると、2つのkeyに対応するhash値が同じでデッドロックが発生する