如果父级先前完成,则子线程似乎无法完成

时间:2017-02-15 21:53:53

标签: java multithreading

我创建了一个EventEmitter,它将事件传递给新线程中的侦听器:

public class EventEmitter{

private Map<String,List<EventListener>> listeners = new HashMap<String,List<EventListener>>();
private Executor executor = Executors.newCachedThreadPool();

protected EventEmitter(Executor executor){
    this.executor = executor;
}

public void publish(Event e) {
    listeners.get(e.getClass().toString()).stream().forEach(listener->{
        executor.execute(()->{listener.beNotifiedOfEvent(e);});
    });
}

public void subscribe(EventListener listener,Class<?> eventClass) {

    assert Arrays.asList(eventClass.getInterfaces()).contains(Event.class);

    List<EventListener> listenersThatListenToIt = listeners.get(eventClass.toString());

    if(listenersThatListenToIt!=null){
        listenersThatListenToIt.add(listener);
    } else {
        listenersThatListenToIt = new ArrayList<EventListener>();
        listenersThatListenToIt.add(listener);
        listeners.put(eventClass.toString(),listenersThatListenToIt);
    }

}
}

我还会在收到事件两秒后在监听器中打印一条消息:

@Component
public class StudentRegisteredEventListener implements EventListener {

@Override
public void beNotifiedOfEvent(Event e) {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    StudentRegisteredEvent studentRegisteredEvent = (StudentRegisteredEvent) e;
    System.out.println("Received student registered event! Student's name is: "+studentRegisteredEvent.getRegisteredStudent());
}

}

我有以下JUnit测试:

    @Test
public void test_emitter_notifies_listener() {
    //given
    EventEmitter emitter = new CachedThreadPoolEventEmitter();
    //StudentRegisteredEvent event = new StudentRegisteredEvent();

    EventListener listener = Mockito.mock(StudentRegisteredEventListener.class);

    Student registeredStudent = new Student();
    registeredStudent.setName("studentName");

    //when
    emitter.subscribe(listener,StudentRegisteredEvent.class);
    emitter.publish(new StudentRegisteredEvent(registeredStudent));

    //then

    System.out.println("end of test");
}

我的问题是当父线程在&#34; beNotifiedOfEvent&#34;结束之前结束时调用,来自侦听器方法的行不打印,所以我只看到&#34;测试结束&#34;在控制台上。

我感兴趣的是:这种行为的原因是什么,以及这是否会在测试环境之外起作用。我计划从Spring MVC控制器发布事件。在父线程完成执行后,这是否可以保证完成?

2 个答案:

答案 0 :(得分:2)

这不是线程终止而是整个过程。 JUnit kills the process when the test finishes,所以甚至非守护程序线程都不能使JUnit测试进程保持活动状态。(如果你仔细想想它就完全是直截了当的,没有人想要在完成实际测试后运行测试进程)。 In Java, threads do not have a hierarchy,没有“父”线程。但是几乎每个应用程序都有某种“主”线程。 JUnit有自己的主线程,在其中运行测试,最后调用System.exit(0);

如果要测试某些定时事件,则必须在测试用例中明确地等待线程。另外,我建议使用ScheduledExecutorService代替Thread.sleep - s。

答案 1 :(得分:1)

如果它在测试环境中不起作用,你不应该接受任何人的说法,它可能在测试环境之外工作。首先让您的测试正常工作。

如果您希望测试正常完成,那么您必须等待它产生的所有线程结束。假设您的Executor实际上是ExecutorService,请按以下步骤操作:

executorService.shutdown();
try 
{
    executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) 
{
    ...
}

当上面的代码正在执行时,您的任务应该运行完成,因此您应该在任务结束之前看到显示的消息。