Java SwingWorker线程可重用性
我想知道当重复执行某个任务时,java SwingWorker及其线程池是如何工作的。下面是问题的SSCE,准备复制+粘贴:Java SwingWorker线程可重用性,java,multithreading,swing,swingworker,Java,Multithreading,Swing,Swingworker,我想知道当重复执行某个任务时,java SwingWorker及其线程池是如何工作的。下面是问题的SSCE,准备复制+粘贴: package com.cgi.havrlantr.swingworkerexample; import java.awt.*; import javax.swing.*; public class Main extends JFrame { public static void main(String[] args)
package com.cgi.havrlantr.swingworkerexample;
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
public Main() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setSize(new Dimension(100,100));
JButton btn = new JButton("Say Hello");
add(btn);
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnPressed(evt);
}
});
}
private void btnPressed(AWTEvent e) {
SayHelloSwingWorker worker = new SayHelloSwingWorker();
worker.execute();
}
private class SayHelloSwingWorker extends SwingWorker<Integer, Integer> {
protected Integer doInBackground() throws Exception {
System.out.println("Hello from thread " + Thread.currentThread().getName());
return 0;
}
}
}
package com.cgi.havrlant.swingworkerexample;
导入java.awt.*;
导入javax.swing.*;
公共类主框架{
公共静态void main(字符串[]args){
invokeLater(new Runnable()){
公开募捐{
new Main().setVisible(true);
}
});
}
公用干管(){
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
设置尺寸(新尺寸(100100));
JButton btn=新JButton(“打招呼”);
添加(btn);
addActionListener(新java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent evt){
btnppressed(evt);
}
});
}
私人无效BTN压力(AWTEvent e){
SayHelloSwingWorker=新的SayHelloSwingWorker();
worker.execute();
}
私有类SayHelloSwingWorker扩展SwingWorker{
受保护的整数doInBackground()引发异常{
System.out.println(“来自线程的Hello”+thread.currentThread().getName());
返回0;
}
}
}
我想问一下下面的问题。每次我在worker的一个新实例上调用execute()(在按下按钮之后),SwingWorker线程池中会创建一个新线程,总共创建10个线程。超过此限制后,线程将按预期重用。因为新的工作线程是在前一个工作线程完成后按顺序创建的,我不明白为什么第一个线程没有立即重用,因为前一个工作线程已经完成了它的工作。假设只有一个线程,它同时执行一些工作。我希望线程池只创建一个线程,这足以服务于所有任务。这是正常的行为吗?或者可能有什么问题,什么会拒绝第一个线程的可重用性,并迫使线程池创建另一个线程
如果这是正常的,我认为创建不需要的线程和保持线程就绪的内存是浪费时间。我能设法避免吗?我能强迫SwingWorker的池中只有一个线程吗我认为不会,因为据我所知,线程的数量是恒定的,并且依赖于Java实现
我可以让SwingWorker在任务完成后完成线程吗?(在done()方法中调用this.cancel()无效)
下面是我的真实世界工作者的代码,以防存在可能导致问题的依赖关系
public class MapWorker extends SwingWorker<Long, Object> {
@Override
protected Long doInBackground() throws Exception{
try {
long requestId = handleAction();
return requestId;
}catch(Exception e){
logger.error( "Exception when running map worker thread.", e);
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
requestFinished();
}
});
MapUtils.showFatalError(e);
}
return -1l;
}
@Override
protected void done(){
try{
requestId = get();
logger.info("Returned from map request call, ID: {}", Long.toString(requestId));
}catch(InterruptedException e){
logger.error( "Done interrupted - wierd!", e);
}catch(ExecutionException e){
logger.error( "Exception in execution of worker thread.", e);
}
}
公共类MapWorker扩展SwingWorker{
@凌驾
受保护的长doInBackground()引发异常{
试一试{
long requestId=handleAction();
返回请求ID;
}捕获(例外e){
logger.error(“运行map worker线程时出现异常。”,e);
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
requestFinished();
}
});
MapUtils.showFatalError(e);
}
返回-1l;
}
@凌驾
受保护的void done(){
试一试{
requestId=get();
info(“从映射请求调用返回,ID:{}”,Long.toString(requestId));
}捕捉(中断异常e){
logger.error(“完成中断-wierd!”,e);
}捕获(执行例外){
logger.error(“工作线程执行中的异常”,e);
}
}
方法中的handleAction()创建了一个带有阻塞调用的新线程,并返回了线程id,这应该没有什么奇怪的。不要问我为什么,这不是我的代码。Hmmm…SwingWorkers的默认ThreadPoolExecutor被配置为不仅最大池大小为10,而且核心大小为10,这意味着它更喜欢保持10个线程处于活动状态。对于让我告诉你为什么,也许在某些条件下它是最优的 您可以使用以下(奇怪的)调用告诉SwingWorkers使用自定义ExecutorService:
注意,Executors.newSingleThreadExecutor()返回的ExecutorService将创建一个非守护进程线程,这可能是您想要更改的。为了更好地帮助您,请尽早发布SSCCE,以验证预期;无需
invokeLater()
;完成()
在EDT上运行。我认为您的链接没有显示相同的问题。此外,AppContext
是sun.awt
软件包,这意味着您在使用它时应该格外小心。除此之外,这似乎是唯一的解决方案。
AppContext.getAppContext().put( SwingWorker.class, Executors.newSingleThreadExecutor() );