Swing中多线程操作UI

Categories: Java; Tagged with: ; @ February 4th, 2009 0:17

通常 Swing 不是线程安全的。除非另行说明,否则所有 Swing 组件及相关类都必须在事件调度线程上访问。

由于Swing不是线程安全的, 因此在实际操作过程中, 应避免通过多线程来操作UI. 在必要时, 应注意要将控件转移到事件调度线程。转移控件和开始处理 Swing 的首选方法是使用 invokeLater

简单的实践:

在如下小程序中, 通过最上方或最下方的Parse 都可以针对某文件或URL进行解析, 并解析出文件中含有的Email, 并归类但因在中间的TextArea中.

在按下Parse时, 将创建一个新的线程, 进行操作.

image

onParse: 为每个请求创建新的线程:

	/** 响应Parse点击或textFilePath回车 - 为每个请求创建一个单独线程 */
	private ActionListener onParse = new ActionListener() {
		public void actionPerformed(ActionEvent e){
			//通过事件来源来判断读取哪个filePath;
			if(e.getSource().equals(buttonParse) || e.getSource().equals(textFilePath)) {
				filePathOnAction = textFilePath.getText();
			}else if(e.getSource().equals(buttonParse2) || e.getSource().equals(textFilePath2)) {
				filePathOnAction = textFilePath2.getText();
			}

			Thread threadParseEmail = new Thread(){ //将为每个请求创造一个线程
				@Override
				public void run() {
					parseEmail(swui.filePathOnAction);
				}
			};
			threadParseEmail.setName("ParseEmail-" + threadParseEmail.getName());
			threadParseEmail.start();

			log.debug("Parse clicked");	//使用log, 便于分辨线程
		}
	};

	 //解析文件, 将ParseEmail返回信息打印到textOutPut中
	private void parseEmail(final String filePath) {
		//buttonParse.setEnabled(false);
		log.info("正在解析");
		labelInfoMessage.setText("正在解析");
		if(labelImage.getIcon() == null) {
			labelImage.setIcon(imageParseing);
		}else {
			labelImage.setVisible(true);
		}
		//TODO Update UI code is put to the AWT-Event Queue so that only the AWT-Event Queue thread executes the UI update code.
		// Other threads may update UI directly but problems may arise in many cases.
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				log.info("Update UI code is put to the AWT-Event Queue so that only the AWT-Event Queue thread executes the UI update code");
				try {
					if(filePath.startsWith("http")) {
						URL romatefile = new URL(filePath);
						textOutput.setText(pe.parseEmailAndReturnDomain(romatefile.openStream()));

					}else {
						textOutput.setText(pe.parseEmailAndReturnDomain(filePath));
					}
					labelInfoMessage.setText("解析完毕");

				} catch (Exception e) {
					log.debug("IO Exception - File does not exist");
					labelInfoMessage.setText("文件不存在, 请确地址是否正确.");
					textOutput.setText("文件不存在, 请确地址是否正确.");
				}

				labelImage.setVisible(false);
			}
		});
	}

log信息:

[AWT-EventQueue-0] DEBUG com.maill.parser.test.UI – Parse clicked  //UI线程

[ParseEmail-Thread-2] INFO  com.maill.parser.test.UI – 正在解析 //表明已经创建新的线程

[AWT-EventQueue-0] INFO  com.maill.parser.test.UI – Update UI code is put to the AWT-Event Queue so that only the AWT-Event Queue thread executes the UI update code //将Thread-2中操作UI的部分交由UI线程处理.

=============================

类似的, 在SWT中, 不允许由非UI线程进行UI操作, 否则将会有Exception抛出. 而在Swing中, 不会抛出任何Exception, 但会产生不安全隐患.

SWT中的event loop flow:

2009-2-13-19-49-17

上图中的Read adn dispatch:

2009-2-13-19-48-32

Java多线程简单应用

Categories: Java; Tagged with: ; @ January 31st, 2009 23:40

需求: 并行处理任务

描述:

某email解析小程序, 点击parse之后会解析网页中或文件中的email地址.

image

如果文件较大或网速较慢, 响应会比较迟钝,出现假死现象, 因此在点击Parse时, 创建一个专门用于Parse的线程, 保证程序的流程运行.

具体解决方法:

1. 监听Parse Button:

buttonParse.addActionListener(onParse);

2.onParse函数

private ActionListener onParse = new ActionListener() {
		public void actionPerformed(ActionEvent e){
			Thread threadParseEmail = new Thread(){

				@Override
				public void run() {
					// TODO Auto-generated method stub
					parseEmail();
				}
			};
			threadParseEmail.setName("ParseEmailThread");
			threadParseEmail.start();
			
			log.debug("Parse clicked");

	};

3.parseEmail函数进行具体的处理.

private void parseEmail() {
		
		log.info("正在解析");
......
	}

log信息:

[AWT-EventQueue-0] DEBUG com.insprise.mail.parser.SwingUI – Parse clicked

[ParseEmailThread] INFO  com.insprise.mail.parser.SwingUI – 正在解析

可见ParseEmail使用单独的进行进行操作,  在解析大文件时 UI不会出现假死状态.



// Proudly powered by Apache, PHP, MySQL, WordPress, Bootstrap, etc,.