我在多线程方面不是很好,这可能是一个基本问题。但是我还没有找到答案。
情境: 假设我有一个事件监听器,它被某些东西激发了。每次触发事件时,我都想启动一个新线程,执行大约需要3秒钟。
问题: 问题是事件可以在一秒钟内多次触发,我不想一次启动多个线程。
要求: 我怎样才能安排一个线程让我们在事件发生后的1000毫秒说出来。如果事件继续发射,我想继续延迟线程的预定时间。这样我的线程在最后一次触发事件的1000ms后执行。
答案 0 :(得分:3)
事件监听器在启动时创建并启动一个新的私有线程。该线程包含要执行的任务列表,并按顺序一次执行一个任务。每次偶数侦听器收到新事件时,它都会创建一个新任务,并将其添加到私有线程中的任务列表中。
编辑:Eugene建议使用线程池,如果你需要花费大量时间完成每项任务的大量工作,这对你的情况可能是有益的。查看Java API中的线程池,如下所示:http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
答案 1 :(得分:2)
我会使用ScheduledExecutorService
- 安排任务在一秒钟内完成,如果有任务已经安排取消,并安排新的任务在一秒钟内完成
这样,您的任务将在上次触发事件后执行一秒钟。
private class Task implements Runnable {
@Override
public void run() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private Future<?> scheduledTaskHandle;
private class Listener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (scheduledTaskHandle != null && !scheduledTaskHandle.isDone()) {
scheduledTaskHandle.cancel(false);
}
scheduledTaskHandle = executorService.schedule(new Task(), 1, TimeUnit.SECONDS);
}
}
Task
是Runnable
,用于执行长时间运行。 Listener
是你的听众类。
在Listener.actionPerformed
方法中,我们首先使用Future
检查任务是否已经安排,如果是,我们取消它。我们不需要担心种族危险,如果任务在调用isDone
和调用cancel
之间完成,则不会发生任何事情。
如果任务在Listener
触发时运行,那么该任务将完成,因为cancel
方法是使用false
调用的。另一项任务将被安排在触发器触发后运行一秒或者当前正在运行的任务完成后(因为我们只使用一个线程,不能运行一个任务)。
然后Listener
将安排任务的新执行在一秒钟内完成。