我创建了一个 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");
}
我的问题是,当父线程在“beNotifiedOfEvent”调用结束之前结束时,不会打印来自监听器方法的行,所以我在控制台上只看到“测试结束”。
我感兴趣的是:这种行为的原因是什么,以及这是否会在测试环境之外起作用。我计划从 Spring MVC Controller 发布事件。这是否保证在父线程完成执行后完成?
最佳答案
不是线程终止而是整个过程。 JUnit kills the process when the test finishes ,所以即使是非守护线程也不能使 JUnit 测试进程保持 Activity 状态。(如果您仔细想想,这完全是直截了当的,没有人希望测试进程在完成实际测试后继续运行)。 In Java, threads do not have a hierarchy ,没有“父”线程这样的东西。然而,几乎每个应用程序都有某种“主”线程。 JUnit 有自己的主线程,在其中运行测试,最后调用 System.exit(0);
。
如果你想测试一些定时事件,你将不得不在测试用例中显式地等待线程。此外,我建议使用 ScheduledExecutorService
而不是 Thread.sleep
-s.
关于java - 如果父线程较早完成,则子线程似乎无法完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42260788/