JAVA - 为什么 SwingWorker 线程不处理所有发布的字符串?

JAVA - Why SwingWorker Thread not processing all publish strings?

我正在使用一个 Worker class,它扩展 SwingWorker 并在它的 process 方法中处理 String 值,并将它们打印到 JTextArea

所以我进行了很多 publish(some_string) 调用以将字符串打印到文本区域,但是当我执行我的工作线程时 - 它不打印我在 doInBackground() 方法中发布的所有文本。它错过了很多发布电话,我只得到了我想要的部分单词。

但是当我执行线程并放置一个断点并且一步步跟随它 我可以看到它确实打印了发布调用中的 所有字符串
做该做的事。

为什么在debug模式下能正常运行,在正常模式下却不行?

我的代码:

public class Worker extends SwingWorker<Void , String>
{
    public Worker(int int optionOfWork){};

    protected Void doInBackground() throws Exception
    {
        ...
        publish("Hellow");
        publish("This is a test");
        ...
        //  a lot of **publish(some_word) calls**   
        ... 
        publish("Some more words");

    }//doInBackground()


    @override
    protected void process(List<String> wordsToPrint)
    {
        String lastWordRecieved = wordsToPrint.get(wordsToPrint.size()-1);
        mainWindowTextArea.append(lastWord);  // not printing\appending all the words sent here by the publish calls
    }


    @override
    protected void done()
    {
        publish("\nDone");
    }

}//Worker class  

我在主线程中所做的就是创建一个 Worker 对象并执行它:

Worker worker = new Worker();

我使用 worker.excute();

启动它

改变这个:

@override
protected void process(List<String> wordsToPrint)
{
    String lastWordRecieved = wordsToPrint.get(wordsToPrint.size()-1);
    mainWindowTextArea.append(lastWord);  // not printing\appending all the words sent here by the publish calls
}

    @override
protected void done()
{
    publish("\nDone");
}

对此:

@override
protected void process(List<String> wordsToPrint) {
    for (String text: wordsToPrint) {
        mainWindowTextArea.append(text + "\n");
    }
}

@override
protected void done() {
    publish("\nDone");
    try {
        get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
}  

for循环一般就是你如何处理传入process方法的String列表。不要忘记在您的 SwingWorker 上调用 get() 如果只是为了检查是否已抛出任何异常。如果仍然卡住,那么是的,创建 post mcve.

您可能需要在 publish(...) 调用之间放置一些 Thread.sleep(10) 以防止调用占用 CPU。

例如:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.*;

@SuppressWarnings("serial")
public class SwingWorkerExample extends JPanel {
    private JTextArea textArea = new JTextArea(30, 40);
    private MyWorker myWorker;

    public SwingWorkerExample() {
        textArea.setFocusable(false);
        JScrollPane scrollPane = new JScrollPane(textArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        JPanel bottomPanel = new JPanel();
        bottomPanel.add(new JButton(new AbstractAction("Start Worker") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (myWorker != null && !myWorker.isDone()) {
                    myWorker.setLoopRunning(false);
                }

                myWorker = new MyWorker();
                myWorker.execute();
            }
        }));
        bottomPanel.add(new JButton(new AbstractAction("Stop Worker") {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (myWorker != null && !myWorker.isDone()) {
                    myWorker.setLoopRunning(false);
                }
            }
        }));

        setLayout(new BorderLayout());
        add(scrollPane);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    private class MyWorker extends SwingWorker<Void, String> {
        private volatile boolean loopRunning = true;

        @Override
        protected Void doInBackground() throws Exception {
            for (int j = 0; j < 1000 && loopRunning; j++) {
                for (int i = 0; i < 1000 && loopRunning; i++) {
                    String text = String.format("My Text %03d", i);
                    publish(text);
                    TimeUnit.MILLISECONDS.sleep(10);
                }
            }
            return null;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String text : chunks) {
                textArea.append(text + "\n");
            }
        }

        @Override
        protected void done() {
            textArea.append("Done\n");

            try {
                get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        public void setLoopRunning(boolean running) {
            this.loopRunning = running;
        }

        public boolean isLoopRunning() {
            return loopRunning;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        SwingWorkerExample mainPanel = new SwingWorkerExample();
        JFrame frame = new JFrame("SwingWorkerExample");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}

您仅附加最后发布的字符串(在给定块中)

 @override
    protected void process(List<String> wordsToPrint)
    {
        String lastWordRecieved = wordsToPrint.get(wordsToPrint.size()-1);
        mainWindowTextArea.append(lastWord);  // not printing\appending all the words sent here by the publish calls
    }

将其更改为

     @override
        protected void process(List<String> wordsToPrint)
        {
            for(String part:wordsToPrint){
             mainWindowTextArea.append(part);
            }
        }

当您调用 publish 时,并不意味着 process 会立即被调用。相反,已发布的条目会被堆叠起来,并在某个时间点作为项目列表传递。