博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swing中的线程并发处理
阅读量:7071 次
发布时间:2019-06-28

本文共 6834 字,大约阅读时间需要 22 分钟。

 

理论解释见官方的文档:

一个Swing程序中一般有下面三种类型的线程:

  •     初始化线程(Initial Thread)
  •     UI事件调度线程(EDT)
  •     任务线程(Worker Thread),可以看成后台其他的线程

        每个程序必须有一个main方法,这是程序的入口。该方法运行在初始化或启动线程上。初始化线程读取程序参数并初始化一些对象。在许多Swing程序中,该线程主要目的是启动程序的图形用户界面(GUI)。一旦GUI启动后,对于大多数事件驱动的桌面程序来说,初始化线程的工作就结束了。

        Swing程序只有一个EDT线程,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
        Swing编程时应该注意以下两点:
1.从其他线程访问UI组件及其事件处理器会导致界面更新和绘制错误。
2.在EDT上执行耗时任务会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
3.应使用独立的任务线程来执行耗时计算或输入输出密集型任务,比如同数据库通信、访问网站资源、读写大树据量的文件。

  从java6开始,SwingWorker类帮你管理任务线程和Swing EDT之间的交互,对于任务线程来说,就是SwingWorker执行和界面无直接关系的耗时任务和I/O密集型操作

一个主界面启动的正确姿势:

public static void main(String[] args) {        SwingUtilities.invokeLater(new Runnable() {            public void run() {                MainFrame mainUI = new MainFrame();                mainUI.showJFrame();            }        });    }

  将任务放到EDT执行的方法是SwingUtilities.invokeAndWait,不像invokeLater,invokeAndWait方法是阻塞执行的,它在EDT上执行Runnnable任务,直到任务执行完了,该方法才返回调用线程。

  invokeLater和invokeAndWait都在事件派发队列中的所有事件都处理完之后才执行它们的Runnable任务,也就是说,这两个方法将Runnable任务放在事件队列的末尾。
  注意:虽然可以在其他线程上调用invokeLater,也可以在EDT上调用invokeLater,但是千万不要在EDT线程上调用invokeAndWait方法!这样做会造成线程竞争,程序就会陷入死锁。那么一个好的办法是不要使用invokeAndWait方法。

一个演示阻塞和非阻塞的例子:

Factorial,用于普通阶乘计算类

package concurrency;public class Factorial {    private int n;         public Factorial(int n) {        this.n = n;    }     public Integer call() {        int result = 1;         for (int i = 1; i <= n; i++) {            result = result * i;        }         try {            Thread.sleep(5000);        } catch (InterruptedException ex) {            ex.printStackTrace();        }                System.out.println("currentThread = " + Thread.currentThread().getName());        return result;    }}

 

一个Callable的阶乘实现类

package concurrency;import java.util.concurrent.Callable;public class FactorialCalculator implements Callable
{ private int n; public FactorialCalculator(int n) { this.n = n; } public Integer call() { int result = 1; for (int i = 1; i <= n; i++) { result = result * i; } try { Thread.sleep(5000); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("currentThread = " + Thread.currentThread().getName()); return result; }}

 

测试类

import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;import javax.swing.JButton;import javax.swing.SwingWorker;import concurrency.Factorial;import concurrency.FactorialCalculator;public class DoBackground {    public DoBackground() {        // TODO Auto-generated constructor stub    }        //线程池处理,阻塞主UI    public static void blockFutureGet() {        ExecutorService pool = Executors.newSingleThreadExecutor();        Future
factorialResult = pool.submit(new FactorialCalculator(8)); try { // Integer factorialValue = factorialResult.get(3, // TimeUnit.SECONDS); Integer factorialValue = factorialResult.get(); System.out.println("Factorial Value (用FutureGet处理) = " + factorialValue); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(); } pool.shutdown(); } //线程池futureTask处理,演示组塞主UI public static void blockFutureTaskGet() { ExecutorService pool = Executors.newSingleThreadExecutor(); FactorialCalculator task = new FactorialCalculator(8); FutureTask
futureTask = new FutureTask
(task); pool.submit(futureTask); pool.shutdown(); try { Integer factorialValue = futureTask.get(); System.out.println("Factorial Value (用FutureTaskGet处理) = " + factorialValue); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(); } } //用主线程处理,阻塞 public static void blockMainThread() { Factorial cal = new Factorial(8); System.out.println("Factorial Value (用主线程处理) = " + cal.call()); } //用FutureGet + swingwork处理 public static void swingworkConcurrency() { final SwingWorker worker = new SwingWorker() { @Override protected Object doInBackground() throws Exception { // TODO Auto-generated method stub ExecutorService pool = Executors.newSingleThreadExecutor(); Future
factorialResult = pool.submit(new FactorialCalculator(8)); try { // Integer factorialValue = factorialResult.get(3, // TimeUnit.SECONDS); Integer factorialValue = factorialResult.get(); System.out.println("Factorial Value (用FutureGet + swingwork处理) = " + factorialValue); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(); } pool.shutdown(); return null; } }; worker.execute(); } //用swingwork线程处理 public static void swingworkMainThread() { final SwingWorker worker = new SwingWorker() { @Override protected Object doInBackground() throws Exception { try { Factorial cal = new Factorial(8); System.out.println("Factorial Value (用swingwork线程处理) = " + cal.call()); } catch (Exception ex) { ex.printStackTrace(); } return null; } }; worker.execute(); } /** * 用swingwork分发线程处理回调,并读写外部的变量值 * @param jbtn,SwingWorker外部的对象 */ public static void swingworkCallback(JButton jbtn) { Integer backInteger; SwingWorker
worker = new SwingWorker
() { @Override protected Integer doInBackground() throws Exception { try { Factorial cal = new Factorial(8); return cal.call(); } catch (Exception ex) { ex.printStackTrace(); } return null; } @Override public void done() { try { System.out.println("Factorial Value (用swingwork分发线程处理回调) = " + get()); //backInteger = (Integer) get(); setTitle(jbtn,get().toString()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; worker.execute(); } static void setTitle(JButton jbtn,String text){ jbtn.setText(text); } }

 

结论:用后两种方法就已经能够实现非阻塞的设计了,即没必要自己再新建线程,或开线程池,请把一切交给swingwork去处理。

最后一个例子演示了回调如何和swing的其他对象(比如说一个jbutton进行数据读写,这是跨线程的操作,swingwork也支持的非常好)。

运行结果:

转载地址:http://pbhll.baihongyu.com/

你可能感兴趣的文章
每天提高
查看>>
postfix事件
查看>>
android log分析
查看>>
步步为营 .NET 代码重构学习笔记 十三
查看>>
053:Field的常用参数详解:
查看>>
读书笔记之SQL必知必会
查看>>
Jquery获取input表单的内容
查看>>
Paint、Canvas
查看>>
关于读写锁算法的java实现及思考
查看>>
最小堆排序
查看>>
iOS-网络爬虫
查看>>
Matlab实现Butterworth滤波器 分类: 图像处理 ...
查看>>
C# for VS foreach 性能对比
查看>>
C#中类和结构体的区别
查看>>
Silverlight 简单布局
查看>>
float学习
查看>>
软件测试之客户体验
查看>>
前端构建工具gulp入门教程
查看>>
LeetCode OJ - LRU Cache
查看>>
iOS边练边学--Http网络再学习,简单介绍
查看>>