Java 使用SwingWorker后的清理

Java 使用SwingWorker后的清理,java,multithreading,swing,unit-testing,swingworker,Java,Multithreading,Swing,Unit Testing,Swingworker,注意:这与终止工作线程无关。这是关于正常终止的后果 我在EDT中调用execute,因此这会产生一个“工作线程”。 我正在一个Callable中调用worker.get(),我将它提交给一个ExecutorService,特别是一个ThreadPoolExecutor 任务正常结束(即worker.get()返回结果,可调用的也正常结束) 我调用Executor服务上的shutdown():方法正常终止 当我在这之后检查线程时,谜题就出现了。这是在单元测试的上下文中进行的,我基本上希望消除在上一

注意:这与终止工作线程无关。这是关于正常终止的后果

我在EDT中调用
execute
,因此这会产生一个“工作线程”。
我正在一个
Callable
中调用
worker.get()
,我将它提交给一个
ExecutorService
,特别是一个
ThreadPoolExecutor

任务正常结束(即
worker.get()
返回结果,可调用的
也正常结束)

我调用
Executor服务上的
shutdown()
:方法正常终止

当我在这之后检查线程时,谜题就出现了。这是在单元测试的上下文中进行的,我基本上希望消除在上一次测试中启动的所有活动

我列出了所有线程,除了测试开始前出现的各种线程外,我还看到了以下内容:

#线程线程[pool-2-thread-1,5,main],状态等待,活动 True,中断False,线程组主线程 线程[SwingWorker-pool-4-Thread-1,5,main],状态等待,活动状态为True, 中断错误,线程组主

问题是,随着测试的运行,新构造的“应用程序”对象每次都会生成一个新的线程池,越来越多的
swingworker
被创建。。。这些线程似乎都没有转换到
线程.State
“TERMINATED”(这可能意味着它们将不再被列出)

然后我尝试在“SwingWorker-pool-4-thread”
线程上调用
join
。。。但这会导致我当前的线程挂起

有人能解释一下这里发生了什么,以及如何将这些线程转换为“终止”线程吗

以后

回复2条有用的评论。10条线,对。我的想法是,如果测试失败(或出现异常),这可能会让事情处于麻烦的状态:假设在功能测试中,涉及3个sw,并且各种
发布/处理
工作正在进行,更不用说EDT中的各种
可运行
s了。在进入下一个测试之前,我希望所有的东西都被关闭、关闭、结束、杀死,回到原始、纯洁的状态

为了确保所有的
Runnable
s都已结束,我们有
Robot.waitForIdle
()。我还想出了一个策略来确保
发布/过程
的事情已经结束:。但事实上,后者虽然有用,但前提是测试代码知道在哪个SWs上调用该方法。。。我在找一辆大炮,它会把他们打死的

这些线程对象的
toString
清楚地显示了自启动最新测试以来创建的线程。。。但我不知道如何杀死他们。“等待”不是意味着,像吸血鬼一样,他们可能会重新站起来,做各种坏事吗?仅仅留下大量的“等待”线程,可能会达到数百条,似乎有点。。。不整洁

甚至以后

啊,是的,掌握
AppContext
对象是至关重要的,因为您需要“重置”该对象以防止
拒绝执行异常
。看看我在Jython的答案

我还注意到,在SW API文档中

因为SwingWorker实现Runnable,所以SwingWorker可以 提交给执行人执行


这可能意味着您根本不必使用SW的默认执行器。这可能是一种方法,但除非在应用程序代码中出于其他原因需要,否则这有点违反了不为测试代码的方便而裁剪应用程序代码的原则…

免责声明:我不确定是否有必要这样做,但是

挖掘了
SwingWorker
源代码后,工作人员使用
private
getWorkersExecutorService
方法获取当前JVM的
ExecutorService

这将使用
AppContext
存储
ExecutorService
的实例,所有
SwingWorker
(对于JVM)的实例都将从中提取线程以执行其功能

所以,如果你做一些像

AppContext appContext = AppContext.getAppContext();
ExecutorService executorService = (ExecutorService) appContext.get(SwingWorker.class);
System.out.println(executorService);
java.util.concurrent.ThreadPoolExecutor@4554617c[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
将打印出类似于

AppContext appContext = AppContext.getAppContext();
ExecutorService executorService = (ExecutorService) appContext.get(SwingWorker.class);
System.out.println(executorService);
java.util.concurrent.ThreadPoolExecutor@4554617c[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
(这假设您以前启动过一个
SwingWorker
,否则它将返回
null

但是,这意味着什么?好了,我们现在可以为所有的
SwingWorker
直接访问
Executor Service
(启示录现在可能开始了)

这意味着您可以关闭服务,甚至可以将其从
AppContext
中删除,例如

SwingWorker worker = new SwingWorker() {
    @Override
    protected Object doInBackground() throws Exception {
        System.out.println("Starting");
        Thread.sleep(10000);
        System.out.println("Ending");
        return null;
    }
};
worker.execute();
synchronized (SwingWorker.class) {
    AppContext appContext = AppContext.getAppContext();
    ExecutorService executorService = (ExecutorService) appContext.get(SwingWorker.class);
    System.out.println(executorService);
    System.out.println("Shutting down");
    executorService.shutdownNow();
    try {
        System.out.println("Waiting");
        executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
        System.out.println("Done");
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
    appContext.remove(SwingWorker.class);
}
在我的测试中,它输出

java.util.concurrent.ThreadPoolExecutor@4554617c[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
Shutting down
Waiting
Starting
Done
所以工人甚至没有机会开始工作。如果我在(调用
execute
后)中放置一个延迟,
shutdownNow
基本上会敲打它,并且不会等待工作人员完成,但是如果我使用
shutdown
它会这样做,因此,您就有了它


我应该补充一点,等待意味着他们什么也没做。在
SwingWorker
的情况下,这些线程是池化的,因此,是的,如果可以的话,工作人员将尝试重新使用它们,但是因为在
SwingWorker
的“正常”操作中,工作人员需要处理
doInBackground
方法可能会爆炸的事实,它已经被设计用于处理它(这就是为什么
get
抛出一个
异常的原因),所以除非您有一个特定的用例,否则我不确定您是否需要这么麻烦,只是说这是对MadProgrammer的回答的回应,为此我感谢他/她

Jython用户可以访问和使用私有方法。下面是获取所有线程,以及获取软件的
ExecutorService

实际上,运行下面的代码表明,“SwingWorker…”线程取消映射