我想在我的Java应用程序中实现以下行为:
单击按钮时,将在新线程中调用任务。但是,如果再次单击该按钮并且当前任务仍在运行,我不想再运行另一个。
我不确定这样做的好方法。目前,我使用的代码类似于下面的代码。
private ExecutorService backgroundTaskExecutor = Executors.newSingleThreadExecutor();
private boolean runningBackgroundTask = false;
private synchronized void setRunningBackgroundTask(boolean running) {
this.runningBackgroundTask = running;
}
private synchronized boolean isRunningBackgroundTask() {
return runningBackgroundTask;
}
private void runBackgroundTask() {
if (isRunningBackgroundTask()) {
System.out.println("This task will be ignored because the thread pool is busy.");
return;
}
Runnable backgroundTask = new Runnable() {
@Override
public void run() {
setRunningBackgroundTask(true);
// Do something that takes time...
setRunningBackgroundTask(false);
}
};
backgroundTaskExecutor.submit(backgroundTask);
}
这是一个好习惯吗? Java中是否有任何实用程序用于此操作?
答案 0 :(得分:2)
使用当前代码,您可能一次最终在执行程序的队列中执行多个任务,因为您检查任务是否在方法开始时运行,但仅在runnable中将其设置为true 。完全有可能在运行runnable的第一行并将状态设置为true之前调用该方法两次。
为确保不会发生这种情况,您可以使用AtomicBoolean
以原子方式获取和设置状态。
private final AtomicBoolean runningBackgroundTask = new AtomicBoolean(false);
private void runBackgroundTask() {
if (runningBackgroundTask.getAndSet(true)) {
System.out.println("This task will be ignored because the thread pool is busy.");
return;
}
Runnable backgroundTask = new Runnable() {
@Override
public void run() {
// Do something that takes time...
runningBackgroundTask.set(false);
}
};
backgroundTaskExecutor.submit(backgroundTask);
}
答案 1 :(得分:1)
虽然Alex发布的解决方案很好,但我想提供一个使用Future
的替代方案。当你想要运行任何(外星人)Runnable
时,它可以被使用,因为它不需要知道'关于runningBackgroundTask
标志:
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Future<?> result;
private void runInBackground(Runnable task) {
if (result != null && !result.isDone()) {
// This task will be ignored because the thread pool is busy
return;
}
result = executor.submit(task);
}
(请注意,result
未同步,因此仅当runInBackground
始终由同一个线程调用时才有效,这在您的情况下是正确的,因为它是由按钮调用的事件处理程序。)