2012-03-29 2 views
0

Я читал в нескольких сообщениях, что использование JUnit для проверки параллелизма не является идеальным, но на данный момент у меня нет выбора. Я только что столкнулся с исключением, которое я не могу объяснить.JUnit и параллелизм: необъяснимая ошибка

Я бег теста, где, в итоге:

  • отправленного 1000 runnables к исполнителю
  • каждому работоспособной добавляет элемент в список
  • я жду окончания исполнителя
  • JUnit говорит, что список содержит только 999 элементов.
  • Исключено исключение в управляемом блоке захвата

Что может вызывать такое поведение?

Примечание: Время от времени я получаю исключение. В коде есть некоторые несвязанные вещи, но я оставил его там, если я что-то пропустил. XXXQuery - это перечисление.

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

Возможно, в определенных ситуациях 10 секунд недостаточно для завершения всех 1000 потоков? – mcfinnigan

+0

В будущем, пожалуйста, предоставьте Exception и покажите, какая строка будет выполнена. Благодарю. – Gray

+0

@mcfinnigan тесты заканчиваются менее чем за секунду. – assylias

ответ

2

Вы не можете добавить к resultsArrayList в вашем Runnable.run() метода в нескольких потоках без синхронизации вокруг него.

Сообщение об ошибке с подтверждением показывает, что хотя были сделаны N_THREADS звонки на add(), у ArrayList было меньше записей из-за условий расы параллелизма.

Я бы использовал конечный массив вместо списка. Что-то вроде:

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

Кроме того, я не совсем получить XXXQuery.values(), но я бы тянуть, что в переменную выше цикла, если он не меняется.

Смежные вопросы