2016-06-20 14 views
1

Das folgende Stück Code funktioniert nicht wie erwartet. Wenn ich die Put-Methode in Does-Klasse aufruft, wird der Wert in der Concurrent-Hash-Map mit verschiedenen Instanzen der Map verknüpft. Was ich versuche, ist, dass mehrere Threads auf dieselbe Map zugreifen und einen Wert für den gleichen Key einfügen. Wenn ich jedoch ein synchronisiertes Schlüsselwort zur Put-Methode hinzufüge, funktioniert es. Was vermisse ich?Einfügen in eine gleichzeitige Hash-Map

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); 
     } 
    } 

} 

Schätzen Sie die Hilfe.

+0

Was funktioniert nicht wie erwartet? Es ist möglich, dass alle 4 Threads erkennen, dass die Karte den Schlüssel nicht enthält, und dann versuchen, sie hinzuzufügen. – ck1

+0

Ja, aber die Put-Methode gilt als Thread-sicher für gleichzeitige Hash-Map. also ich vermute, das sollte kein problem sein? – Krish

Antwort

2

Dieser Code nicht Thread-sicher

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); 
    } 

In Java 8 Sie computeIfAbsent verwenden können.

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

Hinweis: Dies ist noch nicht Thread-sicher wie die Arraylist nicht sicher ist, fädeln, so was Sie brauchen, ist

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

Interessant ist nicht die gleichzeitige Hash-Maps put Methode Thread sicher? Javadoc sagt, dass alle Operationen für die gleichzeitige Hash-Karte threadsicher sind – Krish

+2

@Krish Sie verstehen nicht, was "Thread Safe" bedeutet. Jede einzelne Operation ist Thread-sicher, aber Sie kombinieren sie auf eine Weise, die die Thread-Sicherheit verliert. –

+0

@LouisWasserman Um fair zu sein, haben die Designer von StringBuffer IMHO übersehen. SimpleDateFormat ist möglicherweise nicht threadsicher * weil * sie StringBuffer verwendet haben und erwartet haben, dass sie die Threadsicherheit für sie übernimmt. –