文档章节

java并发编程(八): 图形用户界面应用程序

ihaolin
 ihaolin
发布于 2014/04/02 15:00
字数 1244
阅读 828
收藏 51

图形用户界面应用程序:

  • Swing的数据结构不是线程安全的,因此必须将它们限制在事件线程中
  • 几乎所有的GUI工具包(awt ,swing)都被实现为单线程子系统

为什么GUI是单线程的

  • 当前的GUI框架通过一个事件分发线程(Event Dispatch Thread, EDT)来处理GUI事件。
  • 单线程的GUI框架通过线程封闭机制来实现线程安全性。

串行事件处理:

  • 避免任务执行的时间过长,导致GUI无法响应其他事件。

Swing中的线程封闭机制:

  • Swing组件及数据模型对象(TableModel, TreeModel)也通过线程封闭机制实现线程安全性。
  • Swing中也存在单线程规则以外的情况:

      1. SwingUtilities.isEventDispatchThread, 判断当前线程是否是事件线程。

      2. SwingUtilities.invokeLater, 可以将一个Runnable任务调度到事件线程中执行(可在任务线程中调度)。

      3. SwingUtilities.invokeAndWait, 可以将一个Runnable任务调度到事件线程中执行,并阻塞当前线程直到任务完成(只能从非GUI线程中调用)。

      4. 所有Repaint, Revalidation请求插入队列的方法(任意线程中调用)。

      5. 所有添加删除监听器的方法(可以在任务线程中调用,但监听器本身一定在事件线程中调用)。

短时间的GUI任务:

  • 短时间任务可以在事件线程中执行,长时间任务则放在另一个线程中执行。
  • 模型对象数据对象的控制流。

长时间的GUI任务:

  • 对于长时间任务,可以使用缓存线程池(Executors.newCachedThreadPool)
  • 例如在事件线程中执行任务:
private static ExecutorService exec = Executors.newCachedThreadPool();
...	
button.addActionListener(new ActionListener() {
	@Override
	public void actionPerformed(ActionEvent e) {
		exec.execute(new Runnable() { //执行任务
			@Override
			public void run() {
				doMuchComptation(); //长时间任务
			}

		});
	}
});
  • 我们还希望任务执行前后能有一些响应反馈:
public void actionPerformed(ActionEvent e) {
	button.setText("Loading..."); //设置button表现
	button.setEnabled(false);
	exec.execute(new Runnable() { //执行任务
		@Override
		public void run() {
			try {
				doMuchComptation();
			} finally{
				exec.execute(new Runnable() {
				       @Override
					public void run() { //恢复button表现
						button.setText("Load");
						button.setEnabled(true);
					}
				});
			}
		}
	});
}

 取消:

  • 当任务运行过长时间,用户想取消它,比较简单的办法就是Future
private static ExecutorService exec = Executors.newCachedThreadPool();
private static Future<?> runningTask = null; //任务

startBtn.addActionListener(new ActionListener() {
	@Override
	public void actionPerformed(ActionEvent e) {
		if (runningTask != null){
			runningTask = exec.submit(new Runnable() {
				@Override
				public void run() {
					while (moreWork()){
						if (Thread.currentThread().isInterrupted()){//若中断了
							doClean();
							break;
						}
						doWork();
					}
				}
			});
		}
	}
});
		
stopBtn.addActionListener(new ActionListener() {
	@Override
	public void actionPerformed(ActionEvent e) {
		if (runningTask != null){ 
			runningTask.cancel(true); //取消任务
		}
	}
});

进度标识和完成标识

  • 当任务执行中,我们希望知道进度信息;当任务完成时,我们希望得到一个完成通知。
/**
 * 支持取消,完成通知及进度通知的任务
 */
public abstract class BackgroundTask<T> implements Runnable, Future<T> {
	private final FutureTask<T> computation = new Computation();
	
	/**
	 * 计算任务
	 */
	private class Computation extends FutureTask<T>{
		public Computation() {
			super(new Callable<T>() {
				@Override
				public T call() throws Exception {
					return BackgroundTask.this.compute();
				}
			});
		}
		
		@Override
		protected final void done(){
			GuiExecutor.instance().execute(new Runnable() {
				@Override
				public void run() {
					T value = null;
					Throwable thrown = null;
					boolean cancelled = false;
					try {
						value = get();
					} catch (InterruptedException e) {
					} catch (ExecutionException e) {
						thrown = e.getCause();
					} catch (CancellationException e){
						cancelled = true;
					} finally{
						onCompletion(value, thrown, cancelled);
					}
				}
			});
		}
	}
	
	protected void setProgress(final int current, final int max){
		GuiExecutor.instance().execute(new Runnable() {
			@Override
			public void run() {
				onProgress(current, max);
			}
		});
	}
	
	private void onProgress(int current, int max) {}
	
	private void onCompletion(T value, Throwable thrown,
			boolean cancelled) {}
	
	/**
	 * 计算过程
	 */
	protected abstract T compute();

        ...//Future其他方法
}

SwingWorker:

  • Java Swing中我们可以通过SwingWorker来实现类似上面的取消,完成通知,进度指示等。

看到SwingWorker, 其实就如上面的BackGroundTask:

public abstract class SwingWorker<T, V> implements RunnableFuture<T> {
   ...//实现RunnableFuture接口, T: doInBackground返回的结果类型, V: publish, process的参数类型
}
使用实例可以如下:
SwingWorker<String, Integer> worker 
	= new SwingWorker<String, Integer>(){
		@Override
		protected String doInBackground() throws Exception {
			System.out.println("任务开始");
			// do some computation
			publish(20);
			publish(30);
			//...
			publish(100);
			return "返回计算结果";
		}

		@Override
		protected void process(List<Integer> chunks) {
			//接收publish发送的数据
			for (Integer chunk : chunks){
				//update ui, for example progress bar
				System.out.println(chunk);
			}
		}
				
		@Override
		protected void done() {
			System.out.println("任务完成");
			// do some state change
		}
};
GuiExecutor.instance().execute(worker);
worker.get(); //block to wait results.

共享数据模型

  • Swing中的数据模型有TableModelTreeModel等,且都被封闭在事件线程中。

线程安全的数据模型:

  • 线程安全的数据模型必须在更新模版时产生事件,这样视图才能在数据发生变化后进行更新。

分解数据模型:

  • 如果程序中既包含用于表示的数据模型(如TableModel,TreeModel), 又包含应用程序特定的数据模型,那么这种应用程序就被称为拥有一种分解模型设计
  • 如果一个数据模型必须被多个线程共享,而且由于阻塞一致性复杂度等原因无法实现一个线程安全的模型时,可以考虑使用分解模型设计

其他形式的单线程子系统

  • 可以创建一个专门的线程或一个单线程的Executor来实现。
  • FuturenewSingleThreadExecutor一起使用

不吝指正。

© 著作权归作者所有

ihaolin
粉丝 263
博文 164
码字总数 106524
作品 4
朝阳
高级程序员
私信 提问
加载中

评论(4)

龙芯二号
多谢,正在做swing项目,收藏
matcloud
matcloud
不错,多谢楼主分享
ihaolin
ihaolin 博主

引用来自“navyblue”的评论

有例子,有真相,好!期待swingwork有更多内容

谢谢,demo已附上。

navyblue
navyblue
有例子,有真相,好!期待swingwork有更多内容
Java打包成exe工具软件exe4j

exe4j是一个帮助你集成Java应用程序到Windows操作环境的java可执行文件生成工具,无论这些应用是用于服务器,还是图形用户界面(GUI)或命令行的应用程序。如果你想在任务管理器中及Windows...

javascript1
2014/06/09
749
0
Java 书籍 Top 10

陈皓 http:// blog.csdn.net/haoel 下面是Java Inside上推荐的十本Java书籍(文章来源),我把中文版的也列了出来。 1)Java Language Specification, Third Edition (by James Gosling) 本书...

JavaGG
2009/09/21
12.7K
20
编写你的第一个HelloWorld

写在前面的话 因为Java基础是以后学习框架的基石,因此开个文集首先写写Java基础,本来想直奔基础知识的介绍,但是为了保证知识的完整性,因此从Java安装和运行“hello world”开始(虽然百度...

nanaFighting
2018/06/15
0
0
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
3.9K
8
Java 10大优点—Part4—Java内存模型

在忙着参加在爱沙尼亚进行的 TEDx talk 演讲活动以及在比利时举办的一届非常忙碌的Devoxx 会议的间隙,我将继续推进 Java’s Rocking 的系列博文。 对还没有接触过这个系列博文的读者,不妨先...

foxlee
2013/12/09
398
1

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周五乱弹 ——不知道假装开心,装的像么

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 :天黑了 你很忧愁, 你说世界上, 找不到四块五的妞, 行走在凌晨两点的马路上, 你疲倦地拿着半盒黄鹤楼。#今日歌曲推荐# 《四块...

小小编辑
今天
2.2K
17
64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
69
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
33
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
124
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部