如果池已满,则忽略线程

时间:2014-06-24 22:47:38

标签: java multithreading

我想在我的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中是否有任何实用程序用于此操作?

2 个答案:

答案 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始终由同一个线程调用时才有效,这在您的情况下是正确的,因为它是由按钮调用的事件处理程序。)