有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java 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.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;
            }
        }

    }

我想问一下下面的问题。每次我在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);
        }
    }

在handleAction()方法中,创建了一个带有阻塞调用的新线程,并返回了线程id,这应该不会有什么奇怪的地方。别问我为什么,这不是我的代码。:)


共 (1) 个答案

  1. # 1 楼答案

    嗯。。。SwingWorkers的默认ThreadPoolExecutor不仅配置为最大池大小为10,还配置为核心大小为10,这意味着它更喜欢保持10个线程处于活动状态。我很难说为什么会这样,也许在某些条件下它是最优的

    您可以使用以下(奇怪的)调用告诉SwingWorkers使用自定义ExecutorService:

    AppContext.getAppContext().put( SwingWorker.class, Executors.newSingleThreadExecutor() );
    

    注意,Executor返回的Executor服务。newSingleThreadExecutor()将创建一个非守护进程线程,这是您可能需要更改的