2012-03-29 6 views
0

Ich las ein paar Beiträge, dass die Verwendung von JUnit zum Testen der Nebenläufigkeit nicht ideal ist, aber ich habe keine andere Wahl für jetzt. Ich bin gerade auf eine Ausnahme gestoßen, die ich nicht erklären kann.JUnit und Nebenläufigkeit: unerklärlicher Fehler

Ich betreibe einen Test, bei dem in der Zusammenfassung:

  • Ich lege 1000 Runnables zu einem Testamentsvollstrecker
  • jeder runnable fügt ein Element in eine Liste
  • ich für den Testamentsvollstrecker Beendigung warten
  • JUnit sagt mir, die Liste hat nur 999 Elemente
  • keine Ausnahme ist in der Runnable Catch Block gedruckt

Was könnte dieses Verhalten verursachen?

Hinweis: Ich bekomme von Zeit zu Zeit nur die Ausnahme. Der Code hat etwas nicht verwandtes Zeug, aber ich habe es dort gelassen, falls ich etwas verpasst habe. XXXQuery ist ein enum.

public void testConcurrent() throws InterruptedException { 
    final int N_THREADS = 1000; 
    final XXXData xxxData = new AbstractXXXDataImpl(); 
    final List<QueryResult> results = new ArrayList<>(); 
    ExecutorService executor = Executors.newFixedThreadPool(N_THREADS); 
    for (int i = 0; i < N_THREADS; i++) { 
     final int j = i; 
     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        results.add(xxxData.get(XXXQuery.values()[j % XXXQuery.values().length])); 
       } catch (Exception e) { 
        System.out.println(e); 
       } 
      } 
     }); 
    } 
    executor.shutdown(); 
    executor.awaitTermination(10, TimeUnit.SECONDS); 
    assertEquals(N_THREADS, results.size()); 
} 
+0

vielleicht in bestimmten Situationen 10s ist nicht lang genug für alle 1000 Threads zu vervollständigen? – mcfinnigan

+0

Geben Sie in Zukunft die Ausnahme an und zeigen Sie an, welche Zeile ausgeführt wird. Vielen Dank. – Gray

+0

@mcfinnigan die Tests in weniger als einer Sekunde abgeschlossen. – assylias

Antwort

2

Sie nicht auf die resultsArrayList in Ihrem Runnable.run() Verfahren in mehreren Threads ohne Synchronisierung um es hinzufügen können.

Die Assertion fehlgeschlagen Nachricht zeigt, dass, obwohl N_THREADS Anrufe an add() gemacht wurden, die ArrayList weniger Einträge wegen der Konkurrenz Race-Bedingungen.

Ich würde ein endgültiges Array anstelle einer Liste verwenden. Etwas wie:

final QueryResult[] results = new QueryResult[N_THREADS]; 
for (int i = 0; i < N_THREADS; i++) { 
    ... 
     public void run() { 
      results[j] = data.get(Query.values()[j % Query.values().length]); 
     } 

Auch verstehe ich nicht ganz die XXXQuery.values() aber ich würde das in eine Variable über die Schleife ziehen, es sei denn es verändert sich.