注意这不是终止工作线程。这是关于正常终止的后果。
我在EDT中呼叫execute
,因此产生了“工作线程”
我在worker.get()
中拨打Callable
,我提交给ExecutorService
,特别是ThreadPoolExecutor
。
任务结束OK(即worker.get()
返回结果,Callable
也结束OK)。
我在shutdown()
上调用Executor Service
:方法正常终止。
当我在此之后检查线程时,就会出现这个难题。这是在单元测试的背景下,我基本上想要杀掉上次测试期间开始的所有活动。
我列出了所有线程,除了在测试开始之前出现的各种线程,我看到了这一点:
#thread线程[pool-2-thread-1,5,main],状态WAITING,alive True,中断False,线程组主要#thread 线程[SwingWorker-pool-4-thread-1,5,main],state WAITING,alive True, 中断False,主题组主要
问题是,随着测试的运行,新构造的“Application”对象每次都会创建一个新的线程池,并且越来越多的SwingWorkers
被创建......并且这些线程似乎都没有转换到Thread.State
“终止”(这可能意味着他们将不再列出)。
然后我尝试在“SwingWorker-pool-4-thread”join
上调用Thread
...但这会导致我当前的线程挂起。
有人可以解释这里发生了什么以及如何将这些线程转换为“TERMINATED”吗?
后
回复2条有用的评论。 10个线程,对。我的想法只是测试它是否失败(或发生异常)这会使事情处于一种麻烦状态:假设,在功能测试中,涉及3个SW,并且各种publish/process
内容正在进行中,更不用说美国东部时间的各种Runnable
。在进行下一次测试之前,我想让一切都关闭,关闭,结束,杀死,回到原始的处女状态!
为确保所有Runnable
已结束,我们有Robot.waitForIdle
()。我还想到了确保publish/process
事情已经结束的策略:SwingWorker, done() is executed before process() calls are finished ....但事实上,后者虽然很有用,但预先假定测试代码知道哪些SW调用该方法......我正在寻找一个大错,它只会杀死死神。
这些Thread对象的toString
清楚地显示了自开始最新测试以来创建的内容......但我不知道如何杀死它们。是不是“等待”意味着,吸血鬼一样,他们可能会再起来并做各种各样的坏事?只是留下大量“等待”的线程,可能会遇到数百个,看起来有点......不整洁!
甚至更晚
啊,是的,抓住AppContext
对象至关重要,因为你需要“重置”这个以防止RejectedExecutionException
。请参阅我在Jython中如何做的答案。
我还注意到,在SW API文档中它说
因为SwingWorker实现了Runnable,所以可以使用SwingWorker 提交给执行人执行。
这可能意味着您根本不必使用SW的默认执行程序。可能是要走的路,但除非在应用程序代码中出于其他原因需要,否则为了方便测试代码,它违反了不定制应用程序代码的原则......
答案 0 :(得分:5)
免责声明:我不确定我是否认为有必要这样做,但是......
通过挖掘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]
(假设您之前已开始SwingWorker
,否则会返回null
)
但是,这是什么意思?好吧,我们现在可以直接访问所有ExecutorService
的{{1}}(天启可能现在开始)
这意味着您可以关闭服务,甚至将其从SwingWorker
中删除,例如......
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
它会这样做,那么,那里你有它。
我应该补充一点,AFAIK shutdown
意味着他们什么都不做。在WAITING
的情况下,这些线程被合并,所以,是的,如果可以的话,工作人员将尝试重新使用它们,但是因为在SwingWorker
的“正常”操作中,工作者需要处理SwingWorker
方法可能爆炸性的事实,它已经设计用来处理它(这就是为什么doInBackground
抛出get
),所以除非你有一个特殊的用例,我不确定你是否需要解决这个问题,只是说
答案 1 :(得分:1)
这是对MadProgrammer的答案的回应,我感谢他/她。
Jython用户可以访问和使用私有方法。下面,获取所有主题,并获得SW ExecutorService
。
运行下面的代码确实显示了" SwingWorker ......"由于shutdownNow
,线程在末尾的线程列表中消失。这不会阻止3个新线程在最后持续存在," TimerQueue"," AWT-Windows"和#34; Java2D Disposer" ...但这些都在"系统" ThreadGroup
,唯一的"主要" group thread剩余是当前的线程,所以我说问题(如果有的话)解决了!
def get_all_threads():
private_static_method = java.lang.Thread.getDeclaredMethod( 'getThreads' )
private_static_method.accessible = True
# invoking a static method: one param, None
return private_static_method.invoke( None )
def show_all_threads():
for thread in get_all_threads():
print( ' # ID %d: thread %s, state %s, alive %s, interrupted %s, thread group %s' % (
thread.id, thread, thread.state, thread.alive, thread.isInterrupted(), thread.threadGroup.name,) )
if thread is java.lang.Thread.currentThread():
print( ' # --> current thread' )
class Worker( javax.swing.SwingWorker ):
def doInBackground( self ):
print( 'Starting' )
time.sleep( 3 )
print( 'Ending' )
Worker().execute()
private_static_method = javax.swing.SwingWorker.getDeclaredMethod( 'getWorkersExecutorService' )
private_static_method.accessible = True
exec_serv = private_static_method.invoke( None )
show_all_threads()
exec_serv.shutdownNow()
print( '# shutDownNow ordered...' )
exec_serv.awaitTermination( java.lang.Integer.MAX_VALUE, java.util.concurrent.TimeUnit.DAYS )
print( '# ...terminated' )
show_all_threads()
# now "reset" the AppContext object so future executes won't raise a RejectedExecutionException
app_context = sun.awt.AppContext.getAppContext()
app_context.remove( javax.swing.SwingWorker )