由于Swing不是线程安全的, 因此在实际操作过程中, 应避免通过多线程来操作UI. 在必要时, 应注意要将控件转移到事件调度线程。转移控件和开始处理 Swing 的首选方法是使用 invokeLater
。
简单的实践:
在如下小程序中, 通过最上方或最下方的Parse 都可以针对某文件或URL进行解析, 并解析出文件中含有的Email, 并归类但因在中间的TextArea中.
在按下Parse时, 将创建一个新的线程, 进行操作.
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: