Java SwingWorker线程可重用性

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)

我想知道当重复执行某个任务时,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) {
            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() );