2016-06-20 14 views
1

次のコードは期待どおりに動作しません。 Doesクラスでputメソッドを呼び出すと、同時ハッシュマップの値はマップの異なるインスタンスに関連付けられます。だから私がやっていることは、複数のスレッドが同じマップにアクセスし、同じキーの値を挿入することです。しかし、putメソッドにsynchronizedキーワードを追加すると動作します。私は何が欠けていますか?同時ハッシュマップに挿入

class Does implements Runnable { 
    C2 c2; 

    Does(C2 c2) { 
     this.c2 = c2; 
    } 

    public void run() { 
     c2.put("Hello"); 
    } 

} 

public class C2 { 
    public ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<String, List<String>>(); 

    public static void main(String args[]) { 
     C2 c2 = new C2(); 
     new Thread(new Does(c2)).start(); 
     new Thread(new Does(c2)).start(); 
     new Thread(new Does(c2)).start(); 
     new Thread(new Does(c2)).start(); 

     try { 
      Thread.sleep(3000); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     List<String> lu = c2.map.get("Hello"); 

     System.out.println(lu); 
    } 

    /** 
    * @param string 
    */ 
    public void put(String string) { 
     if (map.containsKey(string)) { 
      List<String> li = map.get(string); 
      li.add("adding something"); 
     } else { 
      List<String> li = new ArrayList<String>(); 
      li.add("adding something"); 
      map.put(string, li); 
     } 
    } 

} 

ヘルプを評価してください。

+0

のですか?すべての4つのスレッドがマップにキーが含まれていないことを確認し、マップを追加しようとする可能性があります。 – ck1

+0

はい、putメソッドは、同時ハッシュマップのスレッドセーフであると言われています。だから私はそれが問題ではないはずだと思いますか? – Krish

答えて

2

このコードは

public void put(String string) { 
    if (map.containsKey(string)) { 
     // anything can happen in another thread here 
     List<String> li = map.get(string); 
     // anything can happen in another thread here 
     li.add("adding something"); 
    } else { 
     // anything can happen in another thread here 
     List<String> li = new ArrayList<String>(); 
     li.add("adding something"); 
     // anything can happen in another thread here 
     map.put(string, li); 
    } 

は、Java 8では、あなたがcomputeIfAbsentを使用することができますスレッドセーフではありません。

public void put(String string) { 
    // all most thread safe. 
    map.computeIfAbsent(string, k -> new ArrayList<>()) 
     .add("add something"); 
} 

注これはまだArrayListのは、スレッドセーフではないとして、スレッドセーフではないので、あなたが必要なものを期待通りに動作していない何

public void put(String string) { 
    List<String> list = map.computeIfAbsent(string, k -> new ArrayList<>()); 
    synchronized(list) { 
     list.add("add something"); 
    } 
} 
+0

面白いのは、スレッドセーフな同時ハッシュマップのメソッドではありませんか? Javadocは、同時ハッシュマップのすべての操作がスレッドセーフであると言います。 – Krish

+2

@Krish "スレッドセーフ"が何を意味するのか分かりません。個々の操作はスレッドセーフですが、スレッドの安全性を失うような方法でそれらを結合しています。 –

+0

@LouisWasserman公正であるために、これはStringBufferのデザイナーがIMHOを見落としたものです。 SimpleDateFormatはStringBufferを使用してスレッド安全性を期待しているため、スレッドセーフではない可能性があります。 –

関連する問題