理论解释见官方的文档:

https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html

一个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<Integer> {
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<Integer> 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<Integer> futureTask = new FutureTask<Integer>(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<Integer> 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<Integer, Object> worker = new SwingWorker<Integer, Object>() { @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也支持的非常好)。

运行结果:

Swing中的线程并发处理的更多相关文章

  1. Java自学-图形界面 Swing中的线程

    Swing中的线程 步骤 1 : 三种线程 在Swing程序的开发中,需要建立3种线程的概念 初始化线程 初始化线程用于创建各种容器,组件并显示他们,一旦创建并显示,初始化线程的任务就结束了. 事件调 ...

  2. swing中的线程

    1. 初始化线程 初始化线程用于创建各种容器,组件并显示他们,一旦创建并显示,初始化线程的任务就结束了. 2. 事件调度线程(单线程:只有一个线程在负责事件的响应工作.) 通过事件监听的学习,我们了解 ...

  3. 【Swing】理解Swing中的事件与线程

    talk is cheap , show me the code. Swing中的事件 事件驱动 所有的GUI程序都是事件驱动的.Swing当然也是. GUI程序不同于Command Line程序,一 ...

  4. 深入浅出Java多线程(2)-Swing中的EDT(事件分发线程) [转载]

    本系列文章导航 深入浅出Java多线程(1)-方法 join 深入浅出Java多线程(2)-Swing中的EDT(事件分发线程) 深入浅出多线程(3)-Future异步模式以及在JDK1.5Concu ...

  5. 【转】Swing 与EDT线程

    在Swing程序中,经常能看到如下这种代码: SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { text ...

  6. 【代码总结● Swing中的一些操作与设置】

    Swing中设置关闭窗口验证与添加背景图片 package com.swing.test; import java.awt.EventQueue; import java.awt.Image; imp ...

  7. Stream入门及Stream在JVM中的线程表现

    继上次学习过Java8中的非常重要的Lambda表达式之后,接下来就要学习另一个也比较重要的知识啦,也就如标题所示:Stream,而它的学习是完全依赖于之前学习的Lambda表达式. 小实验引入: 这 ...

  8. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  9. rxjava源码中的线程知识

    rxjava源码中的线程知识 rx的最精简的总结就是:异步 这里说一下以下的五个类 1.Future2.ConcurrentLinkedQueue3.volatile关键字4.AtomicRefere ...

随机推荐

  1. JS 操作样式 style

    1. 任何支持 style 特性的 HTML 元素在 JavaScript 中都对应着有一个 style 属性,指向一个 CSSStyleDeclaration 的一个实例对象,包含该元素的内嵌sty ...

  2. maven 项目打包到本地仓库并且推送到私服仓库

    首先进入到项目文件夹下,然后进入cmd命令窗口,第一步先clean一下,输入命令 mvn clean. 第二步打包到本地,输入命令mvn clean package -Dmaven.test.skip ...

  3. Python设计模式 - UML - 类图(Class Diagram)

    简介 类图是面向对象分析和设计的核心,用来描述系统各个模块中类与类之间.接口与接口之间.类与接口之间的关系,以及每个类的属性.操作等特性,一般在详细设计过程中实施. 类图本身就是现实世界的抽象,是对系 ...

  4. Power designer 的使用

    1.Powere Designer 逆向 工程 首先 逆向工程 就是将数据库表 导入到模型, 首先新建个模型, 此处就省略 ... 工具栏,数据库(database) 下的 update model ...

  5. eclipse定制化配置调优、初始化配置指南、可以解决启动慢等问题

    配置eclipse的jvm参数 打开eclipse根目录下的eclipse.ini在最后面加上如下的jvm参数 -Xms400m -Xmx1400m -XX:NewSize=128m -XX:MaxN ...

  6. maven 监理web war 项目

  7. surf the internet scientifically

    You can get some useful information from the link below: 1. http://blog.sina.com.cn/s/blog_4891cbc50 ...

  8. PHP-循环结构-数组(难)

    今日目标: (1)循环结构 —— do..while.. —— 掌握 (2)循环结构 —— for —— 重点 (3)数组 —— 重点 1.PHP中的循环结构 —— do..while... do: ...

  9. 单色三角形(hdu-5072

    单色三角形模型:空间里有n个点,任意三点不共线.每两个点之间都用红色或者黑色线段链接.如果一个三角形的三条边同色,责成这个三角形是单色三角形.对于给定的红色线段列表,找出单色三角形的个数. 分析:对于 ...

  10. SAS 逻辑库

    SAS逻辑库 SAS逻辑库是一个或多个SAS文件的集合,用于组织.查找和管理 SAS文件.SAS逻辑库管理的SAS文件包括SAS数据集.SAS目录.已编 译的SAS程序,以及多维数据库文件等. 1.逻 ...