UI线程中非安全操作与安全操作

------------------siwuxie095

   

   

   

   

   

   

   

工程名:SwingUIThreadSafeTest

包名:com.siwuxie095.swinguithread

类名:MyFrame.java

   

   

工程结构目录如下:

 

   

   

   

   

代码:

   

package com.siwuxie095.swinguithread;

   

import java.awt.BorderLayout;

import java.awt.EventQueue;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

   

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JProgressBar;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;

import javax.swing.border.EmptyBorder;

   

import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;

   

//MyFrame 直接继承自 JFrame

public class MyFrame extends JFrame {

   

private JPanel contentPane;

   

/**

* Launch the application.

*/

 

public static void main(String[] args) {

 

EventQueue.invokeLater(new Runnable() {

public void run() {

try {

MyFrame frame = new MyFrame();

frame.setVisible(true);

} catch (Exception e) {

e.printStackTrace();

}

}

});

 

}

   

/**

* Create the frame.

*/

public MyFrame() {

 

try {

UIManager.setLookAndFeel(new WindowsLookAndFeel());

} catch (UnsupportedLookAndFeelException e) {

e.printStackTrace();

}

 

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setBounds(100, 100, 450, 300);

contentPane = new JPanel();

contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));

contentPane.setLayout(new BorderLayout(0, 0));

setContentPane(contentPane);

 

JProgressBar progressBar = new JProgressBar();

contentPane.add(progressBar, BorderLayout.NORTH);

 

JButton btnRun = new JButton("Run");

 

//为按钮 Run 添加 mouseClicked 事件

btnRun.addMouseListener(new MouseAdapter() {

@Override

public void mouseClicked(MouseEvent e) {

/*********************************************************

* 非安全操作(1)

*

* 点击 Run 按钮后,该按钮不会弹起,进度条也不会增加,即 界面卡死,没有任何反应

* 直到 10 秒后,Run 按钮弹起,进度条直接跳到满格,中间的所有过程都没有被展示

*

* 出现这种情况的原因:当为鼠标添加的事件触发后,调用 mouseClicked()方法,

* 该方法也是被当前的UI线程所执行的,一旦UI线程中出现了 类似 sleep(1000) 这样的阻塞方法,

* 将造成UI线程一直在阻塞的地方等待 ,而不会执行任何界面刷新的工作,这就导致了界面卡死的现象

*

* 如果要编写一个响应良好的界面,不能在UI线程中执行非常耗时的操作

* 如:等待、UI的读写、网络的读写

*

* 如果一定要执行等待、或每隔多长时间执行一个特殊的动作,可以使用 Swing Timer 进行操作

* 如果需要读取大量的网络数据,或读写本地文件,可以创建一个新的线程 SwingWorker

*********************************************************

*/

 

// //(1)只需点击一次按钮

// for (int i = 1; i <= 10; i++) {

// try {

// //1 秒进度条增加一格

// //有异常抛出,用 try catch 捕获

// Thread.sleep(1000);

// progressBar.setValue(i*10);

// } catch (InterruptedException e1) {

// e1.printStackTrace();

// }

// }

 

 

/*********************************************************

* 安全操作(2)

*

* 在为界面中的元素添加的监听器(各种事件)触发所产生的回调方法

* 都是由 Swing 的事件派发线程(UI线程)来完成的

*

* UI线程中可以非常安全操作任何元素的属性

* 如:让进度条根据自己的 value 10

*********************************************************

*/

 

//(2)需要连续点击按钮

progressBar.setValue(progressBar.getValue()+10);

 

 

}

});

 

btnRun.setFocusable(false);

contentPane.add(btnRun, BorderLayout.SOUTH);

}

   

}

   

   

   

将窗体 JFrame 的 LookAndFeel 设定为 Windows

   

   

在根面板 contentPane 的上方添加一个 JProgressBar,

下方添加一个 JButton

   

   

将 JButton 的文本(text)改为 Run,并 Rename 为 btnRun,

将 focusable 属性设为 false

   

   

为 JButton 添加 mouseClicked 事件,当点击 Run 按钮时,进度条的增加

   

   

非安全操作:

   

   

   

运行程序:

点击 Run 按钮后,按钮不会弹起,进度条也不会增加,

界面卡死。直到 10 秒后,Run 按钮才弹起,进度条

直接跳到满格

   

   

   

界面卡死的原因:

   

当为鼠标添加的事件触发后,调用 mouseClicked() 方法,

该方法也是被当前的 UI 线程所执行的

   

一旦 UI 线程中出现类似 Thread.sleep(1000); 这样的阻塞方法,将

造成 UI 线程一直在阻塞处 Thread.sleep(1000); 等待 ,而不会执行

任何界面刷新的工作,进而导致界面卡死

   

   

   

安全操作:

   

   

   

运行程序:

   

   

   

   

   

   

因界面中元素的监听器(各种事件)触发所产生的回调方法都是

由 Swing 的事件派发线程(UI 线程)来完成的

   

「事件派发线程 Event Dispatch Thread,简称 EDT」

   

所以,如果要编写一个响应良好的界面,不能在 UI 线程中执行非常耗时的操作

   

如:等待、文件的读写、网络数据的读写

   

 

如果一定要执行等待、或 每隔一定时间执行一个特殊的动作,可以

使用 Swing 的 Timer 进行操作

   

   

如果需要读取大量的网络数据,或 读写本地文件,可以

使用 Swing 的 SwingWorker 进行操作

   

   

   

   

   

   

   

   

【made by siwuxie095】

原文地址:https://www.cnblogs.com/siwuxie095/p/6674081.html