2013-05-17 1 views
13

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

public class Test { 
    @org.junit.Test 
    public void TestThreads() { 
     new Thread(new Runnable() { 
      public void run() { 
       for (int i = 1; i < 1000; i++) System.out.println(i); 
      } 
     }).start(); 
    } 
} 

Если я запустил этот модульный тест, он, как правило, перестанет отображать вывод где-то между 140-180. Если я конвертирую этот код в обычный класс и запускаю его, он отлично работает. Кто-нибудь знает, что мне здесь не хватает?

Thanks, - Andrew.

ответ

0

Возможно, что заканчивается родительская нить, выполняющая тест. Если вы можете избежать этого, не создавайте в тестах новый поток. Я бы создал новый класс, реализующий runnable, а затем проверил этот класс, который я просто вызывал на этом объекте. Вам не нужно проверять планирование потоков как часть ваших тестов. Надеюсь, команда разработчиков java-языка у вас есть.

6

В функции TestThread JUnit не имеет права сообщать, что вы породили новую тему. Он восстанавливает любые объекты, созданные в функции, как только функция заканчивается (последняя строка достигнута) и не знает о потоке.

По этой причине вы видите Output from the Thread, пока он не будет убит. Если вы хотите дождаться завершения проекта, вы можете использовать Thread.join (сразу после того, как вы позвоните Thread.start()), чтобы подождать результата или использовать wait-notify на каком-то объекте.

Кроме того, нашел этот вопрос: JUnit terminates child threads

+0

Сказать, что объекты JUnit 'deletees' немного вводят в заблуждение, поскольку в Java нет способа явно удалить объект. –

+0

@Martin правый. но JVM может вернуть (GC), когда объект больше не нужен. Как только тесты будут выполнены, JUnit убивает потоки и в основном весь JVM. – goblinjuice

+0

@goblinjuice, что не означает, что JUnit вообще убивает экземпляр объекта. Поскольку JVM завершает работу, каждый бит памяти будет освобожден. –

22

Вы можете использовать Thread.join() предотвратить испытание от отделки до нового нить выполнила свою задачу:

@org.junit.Test 
public void TestThreads() throws InterruptedException { 
    Thread t = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 1; i < 1000; i++) System.out.println(i); 
     } 
    }); 
    t.start(); 
    t.join(); 
} 

Обычно, виртуальная машина будет прекратить, когда последний non-daemon thread завершается. Вы могли бы ожидать, что просто вызов t.setDaemon(false) в потоке не позволит JVM выйти из игры до завершения задачи. Однако junit будет call System.exit(), когда закончится основной поток.

Как отмечает Гас в комментариях: «вам нужно join(), потому что start() не блокирует».

Он прав, что вы также можете позвонить run() в этом минимальном примере. Однако я предполагаю, что вы начинаете поток, потому что хотите, чтобы он запускался одновременно с другим потоком. Вызов run() в теме помечен как возможная ошибка FindBugs - если вы только собираетесь позвонить run(), вы, вероятно, просто захотите реализовать Runnable вместо использования Thread.

+0

Вздох - избили меня на ярмарке и площади. –

+1

Стоит упомянуть в вашем решении, что вам нужно Join(), потому что Start() не блокирует. IIRC, вы также можете просто использовать Run(), если вы не собираетесь делать что-либо одновременно. – Gus

+0

@Gus, использующий 'run' на экземпляре' Thread' - плохая идея. Зачем?Потому что использование 'run' не делает его потоком, просто простым объектом. –

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