Swing使用SwingWorker执行多线程异步任务

参考文章:swingworker_使用SwingWorker的Java Swing中的多线程

使用SwingWorker为界面执行异步任务

简介:

SwingWorker是一个专门为界面而实现的线程类,
它可以非常方便的在当前的UI线程中新建异步线程执行一定的耗时操作,且可以很安全的将它的返回值发送给UI线程。

SwingWorkerTaskMgt.java

package org.fiend.swing.test.demo.swingworker.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;

/**
 * @author pelang 2021-09-22 14:50:16
 */
public class SwingWorkerTaskMgt {
    private static final Logger logger = LoggerFactory.getLogger(SwingWorkerTaskMgt.class);

    private static JFrame frame;
    private static JTextArea textArea;
    private static JProgressBar progressBar;

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        initUI();

        SwingWorkerDemo task = new SwingWorkerDemo(textArea);
        task.addPropertyChangeListener(
                new PropertyChangeListener() {
                    public void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equals(evt.getPropertyName())) {
                            progressBar.setValue((Integer) evt.getNewValue());
                        }
                    }
                }
        );

        /*
         * 判断立即执行任务是否启动swingWorker
         * SwingWorker的状态只有三种: PENDING, STARTED, DONE
         *   PENDING: 刚刚初始化, 尚未运行
         *   STARTED: 正在运行中
         *   DONE: 运行结束, 包括正常运行结束, 异常运行结束, 强制终止结束
         */
        String msg;
        SwingWorker.StateValue state = task.getState();
        logger.info("SwingWorker state: " + state);

        if (state == SwingWorker.StateValue.STARTED) {
            msg = "The task is running!";
            logger.info(msg);
            return;
        }

        if (state == SwingWorker.StateValue.DONE) {
            task = new SwingWorkerDemo(textArea);
        }

        // 任务开始执行
        task.execute();
        System.out.println(task.get()); // prints all numbers we have got
    }

    private static void initUI() {
        frame = new JFrame("SwingWorker Test");
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel jp = new JPanel(null);
        jp.setBackground(Color.WHITE);

        textArea = new JTextArea();
        textArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(
                textArea,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
        );
        scrollPane.setBounds(10, 50, 360, 200);

        progressBar = new JProgressBar(0, 100);
        progressBar.setBounds(10, 0, 360, 20);

        jp.add(scrollPane);
        jp.add(progressBar);

        frame.add(jp);
        frame.setVisible(true);
    }
}

SwingWorkerDemo.java

package org.fiend.swing.test.demo.swingworker.test;

import javax.swing.*;
import java.util.List;

/**
 * 类 SwingWorker<T,V>
 * 类型参数:
 * * T - 此 SwingWorker 的 doInBackground 和 get 方法返回的结果类型
 * * V - 用于保存此 SwingWorker 的 publish 和 process 方法的中间结果的类型
 * *
 * * SwingWorker是一个专门为界面而实现的线程类,
 * * 它可以非常方便的在当前的UI线程中执行一定的耗时操作,且可以很安全
 * * 的将它的返回值发送给UI线程
 * *
 * * 创建SwingWorker时,需要指定两个泛型:
 * *    第一个泛型是SwingWorker线程执行之后得到的结果的类型(返回值的类型)
 * *    第二个泛型是SwingWorker线程执行中间所发布(publish)的数据的类型
 * *
 * * 这里将整个SwingWorker的返回值定义为StringBuilder,中间发布的数据定义为String
 * *
 * * 覆盖三个方法:doInBackground()、process()、done()
 * *
 * * doInBackground()
 * *  返回计算结果;如果无法生成计算结果,则抛出异常。
 * *  注意,此方法只执行一次。
 * *  注:此方法在后台线程中执行。
 * <p>
 * 执行耗时的操作,如:读取网络数据、读取本地文件、等待
 * *    产生的中间数据 publish() 到 process() 中
 * *    返回值在 done() 中被 get() 到
 * *    即两种方法都能获取最终的结果
 * *    最后调用SwingWorker的 execute() 方法执行该线程
 * *
 * * done()
 * *    doInBackground 方法完成后,在事件指派线程 上执行此方法。
 * *
 * * process(List<V> chunks)
 * *    在事件指派线程上异步地从 publish 方法接收数据块。
 * *
 * * publish(V... chunks)
 * *    将数据块发送给 process(java.util.List) 方法。
 * *
 * @author pelang 2021-09-09 16:47:59
 */
public class SwingWorkerDemo extends SwingWorker<String, Integer> {
    private static final int numbersToFind = 30;
    private static Boolean enough = false;
    private final JTextArea textArea;

    public SwingWorkerDemo(JTextArea textArea) {
        this.textArea = textArea;
    }

    /**
     * 此方法执行耗时操作。
     * 此方法只执行一次。
     *
     * 返回计算结果;如果无法生成计算结果,则抛出异常。
     * * *  注意,此方法只执行一次。
     * * *  注:此方法在后台线程中执行。
     * * <p>
     * * 执行耗时的操作,如:读取网络数据、读取本地文件、等待
     * * *    产生的中间数据 publish() 到 process() 中
     * * *    返回值在 done() 中被 get() 到
     * * *    即两种方法都能获取最终的结果
     * * *    最后调用SwingWorker的 execute() 方法执行该线程
     * @return
     */
    @Override
    public String doInBackground() {
        int number = 0;

        while (!enough && !isCancelled()) {
            number++;
            publish(number);

            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 设置"progress"属性
            setProgress(number);
        }

        System.out.println("enough: -----> " + enough);
        return String.valueOf(number);
    }

    @Override
    protected void process(List<Integer> list) {
        for (Integer i : list) {
            textArea.append(i + "\n");
            if (numbersToFind == i) {
                enough = true;
            }
        }
    }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风情客家__

原创不易,觉得好的话给个打赏哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值