1

我正在使用线程池大小为 1 的 ThreadPoolExecutor 来顺序执行摇摆工作人员。我遇到了一个特殊情况,即一个事件到达,它创建了一个执行一些客户端-服务器通信的 swing worker,然后更新 ui(在 done() 方法中)。

当用户触发(单击项目)某些事件但如果发生许多事件时,这可以正常工作。但这发生了,所以我需要取消所有当前正在运行和计划的工作人员。问题是支持 ThreadPoolExecutor 的队列不知道 SwingWorker 取消过程(至少看起来是这样)。所以预定的工人会被取消,但已经在运行的工人不会。

所以我添加了一个类型的并发队列,<T extends SwingWorker>它保存所有工作人员的引用,只要它们没有被取消,并且当新事件到达时,它会在队列中的所有 SwingWorkers 上调用 .cancel(true) 并将新的 SwingWorker 提交给 ThreadPoolExecutor。

摘要: SwingWorkers 是在具有单个线程的 ThreadPoolExecutor 中创建和执行的。只有最后提交的工作人员才应该运行。

有没有其他方法可以解决这个问题,或者这样做是否“可以”?

只是好奇...

4

4 回答 4

2

创建仅执行最后一个传入 Runnable 的单线程 ThreadPoolExecutor 的一种方法是子类化一个合适的队列类并覆盖所有添加方法以在添加新的 runnable 之前清除队列。然后将该队列设置为 ThreadPoolExecutor 的工作队列。

于 2009-08-20T18:53:40.223 回答
0

为什么需要 ThreadPoolExecutor 来完成这种工作?

你有多少不同 SwingWorkers 的来源?因为如果源只是一个,你应该使用不同的方法。

例如,您可以定义一个处理一种工作线程的类,并将其链接到一种项目,用户可以在该项目上触发操作并在该类内部关心线程的单个实例应该运行的事实(例如使用完成任务后清除的单例实例)

于 2009-06-18T14:35:05.067 回答
0

除了使用 SwingWorker 之外,您是否可以不使用 ThreadPoolExecutor 来执行客户端-服务器通信,然后调用 SwingUtilities.invokeLater 来使用结果更新 UI?这对我来说似乎更干净一些,并且可以确保事件和 UI 更新仍然按顺序处理。

当您向执行者提交任务时,您可以保留对它们的 Future 实例的引用,以便您可以在需要时取消任务。

于 2009-06-18T21:46:12.320 回答
0

让我看看我是否正确理解了这个问题。您有一个 FIFO 任务队列,其中只有最旧的任务正在运行。每个任务完成后都需要更新 UI。但是如果某个用户事件进来了,所有的任务都需要被取消——也就是正在运行的任务需要被取消,尚未运行的任务需要从队列中移除。是对的吗?

假设是这样,我不会使用,SwingWorker因为您只需要一个工作线程,而不是每个任务一个。FutureTask应该足够了(假设您重写done()以进行必要的调用SwingUtilities.invokeLater()并进行 UI 更新)。

如果你取消 a FutureTask,那么即使它的run()方法被调用,它也不会做任何事情。因此,您可以FutureTask安全地将 s 提交给ExecutorService知道即使执行程序尝试运行它们,取消也会起作用。

我怀疑一个足够好的解决方案只是保留所有FutureTasks可能需要取消的列表,并在用户事件出现时将它们全部取消。ExecutorService仍然会尝试运行它们,但基本上不会-操作。您需要确保已从列表中删除已完成的任务,并且您需要确保列表已更新并以线程安全的方式使用(可能来自将任务放在的同一线程ExecutorService),但这不应该是太难。

我只用了一个小时就把下面的代码搞砸了,我不敢打赌它是正确的,但你明白了。:)

/** Untested code! Use at own risk. */
public class SwingTaskExecutor {

    // ////////////////////////////////////////////////////////////
    // Fields

    private final ExecutorService execSvc = Executors.newFixedThreadPool(1);

    private final Lock listLock = new ReentrantLock();
    private final List<ManagedSwingTask<?>> activeTasks = 
            new ArrayList<ManagedSwingTask<?>>();

    // ////////////////////////////////////////////////////////////
    // Public methods

    public <T> Future<T> submit(SwingTask<T> task) {
        ManagedSwingTask<T> managedTask = new ManagedSwingTask<T>(task);
        addToActiveTasks(managedTask);
        execSvc.submit(managedTask);
        return managedTask;
    }

    public void cancelAllTasks() {
        listLock.lock();
        try {
            for (ManagedSwingTask<?> t: activeTasks) {
                t.cancel(true);
            }
            activeTasks.clear();
        } finally {
            listLock.unlock();
        }
    }

    // ////////////////////////////////////////////////////////////
    // Private methods

    private <T> void addToActiveTasks(ManagedSwingTask<T> managedTask) {
        listLock.lock();
        try {
            activeTasks.add(managedTask);
        } finally {
            listLock.unlock();
        }
    }

    // ////////////////////////////////////////////////////////////
    // Helper classes

    private class ManagedSwingTask<T> extends FutureTask<T> {

        private final SwingTask<T> task;

        ManagedSwingTask(SwingTask<T> task) {
            super(task);
            this.task = task;
        }

        @Override
        public void cancel(boolean mayInterruptIfRunning) {
            try {
                task.cancel();
            } finally {
                super.cancel(mayInterruptIfRunning);
            }
        }

        @Override
        protected void done() {
            removeFromActiveTasks();
            updateUIIfDone();
        }

        private void removeFromActiveTasks() {
            listLock.lock();
            try {
                activeTasks.remove(this);
            } finally {
                listLock.unlock();
            }
        }

        private void updateUIIfDone() {
            if (isDone()) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        task.updateUI();
                    }
                });
            }
        }
    }

    public static interface SwingTask<T> extends Callable<T> {

        /** Called from the EDT if task completes successfully */
        void updateUI();

        /** Hook in case there's task-specific cancellation to be done*/
        void cancel();
    }
}

反正就是这样。

如果您想更加确定,则可以关闭并更换ExecutorService,但这可能没有必要。

于 2009-07-31T15:57:22.197 回答