2016-05-05 6 views
1

Ich weiß, dass TreeMap nicht Thread sicher ist. Ich versuche einen Vergleich von TreeMap mit ConcurrentSkipListMap zu machen. Code, den ich benutze, wird unten gezeigt und ich möchte sicherstellen, dass der Fehler, den ich erhalte, darauf zurückzuführen ist, dass TreeMap nicht threadsicher ist und nicht wegen anderer.Ist diese Nullzeiger-Ausnahme in TreeMap aufgrund des gleichzeitigen Zugriffs?

Exception in thread "pool-1-thread-52" java.lang.NullPointerException bei java.util.TreeMap.rotateLeft (TreeMap.java:2060) bei java.util.TreeMap.fixAfterInsertion (TreeMap .java: 2127) bei java.util.TreeMap.put (TreeMap.java:574) bei ThreadTestTreeMap $ 1.run (ThreadTestTreeMap.java:39) bei java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java: 1145) bei java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:615) bei java.lang.Thread.run (Thread.java:745)

import com.google.common.collect.Ordering; 
import java.util.Map; 
import java.util.TreeMap; 
import java.util.concurrent.ConcurrentSkipListMap; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.TimeUnit; 

public class ThreadTestTreeMap { 
    public static Map<String, Object> map; 
    public static int THREADS = 100; 
    public static long averageTime = 0; 

public static void main(String args[]) throws InterruptedException { 
    for (int i = 0; i < 1; i++) { 
     map = new TreeMap<>(Ordering.natural()); 
//   map = new ConcurrentSkipListMap<>(Ordering.natural()); 

     long time = System.nanoTime(); 
     ExecutorService service = Executors.newFixedThreadPool(THREADS); 

     for (int j = 0; j < THREADS; j++) { 
      final int finalJ = j; 
      service.execute(new Runnable() { 
       public void run() { 
        try { 
         Thread.sleep(THREADS - finalJ); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
        long threadId = Thread.currentThread().getId(); 
        map.put("tag"+threadId, "hello"); 
      }}); 
     } 
     service.shutdown(); 
     service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
     long timeUsed = (System.nanoTime() - time)/1000000L; 
     averageTime += timeUsed; 
     System.out.println("All threads are completed in " 
       + timeUsed + " ms"); 
    } 
    System.out.println("The average time is " + averageTime/10 + " ms"); 
} 
} 
+0

synchronisieren Zugriff mit synchronisiertem (Karte) {map.put ("tag" + ThreadID, "Hallo"); } und führen Sie den zu überprüfenden Code erneut aus. Wie auch immer, TreeMap ist nicht threadsicher, daher ist GARANTIERT, dass Sie einen Fehler erhalten (NullPointerExcaption oder jede andere Ausnahme oder logischer Fehler, es hängt von der Implementierung ab, siehe Quellen) während gleichzeitiger Änderung. Tatsächlich erhalten Sie undefiniertes Verhalten mit einer Reihe von möglichen Fehlern. – AnatolyG

+2

@AnatolyG Nein, es ist nicht garantiert, dass Sie * eine Ausnahme oder einen logischen Fehler erhalten *; es ist einfach nicht garantiert, dass Sie nicht werden. –

+0

@Andy :) Buchstäblich ja, du hast Recht. Aber das macht mir nichts aus, wenn ich meinen Code schreibe. Ich erwarte das schlimmste MÖGLICHE Szenario. Und du siehst, wie leicht es passiert ist. – AnatolyG

Antwort

4

Ob die NullPointerException ein direktes Ergebnis der gleichzeitigen Änderung ist, heißt es in the Javadoc for TreeMap:

Beachten Sie, dass diese Implementierung nicht synchronisiert ist. Wenn mehrere Threads gleichzeitig auf eine Map zugreifen und mindestens einer der Threads die Map strukturell ändert, muss extern synchronisiert werden.

Während Sie die Map in mehreren Threads ohne Synchronisierung bearbeiten, verwenden Sie die Klasse nicht so, wie sie verwendet werden soll.

hinzufügen externe Synchronisation :)

+0

Danke. Eigentlich weiß ich, dass TreeMap nicht threadsicher ist. Ich plane nicht, es in einer konkurrierenden Umgebung zu verwenden. Ich möchte nur wissen, was der Fehler wäre, wenn ich es in einer gleichzeitigen Umgebung verwende. Ich erhalte einen ähnlichen Fehler in einem Java-Client (influxdb-java) https://github.com/influxdata/influxdb-java. Daher möchte ich sicherstellen, dass dieser Fehler aufgrund der Verwendung von TreeMap in dieser Quelle auftritt. –

+1

Wenn Sie die Klasse nicht verwenden, da die Dokumentation besagt, dass sie verwendet werden soll, sind Sie auf sich gestellt. Es gibt keine Garantien darüber, was passieren wird. Wenn Sie sehen wollen, ob es wegen * nicht * Synchronisierung hat .... sehen Sie, ob es immer noch passiert, wenn Sie die Synchronisation hinzufügen. –