Swing multithreaded programming

    Basically all GUI libraries are single-threaded, and Swing is a GUI library. What does that mean? That is to say, all updates to the UI are performed in the main thread, which is why Swing's EDT thread (event dispatch thread) is also called the UI thread. If you perform time-consuming operations in the UI thread, the interface will get stuck. Swing has a single-threaded specification, just keep in mind that it will avoid many big pits: all interface operation updates should be performed in the EDT thread, and all time-consuming operations should be performed in a separate thread.

     Remember the red part above, and then we start an example: after the button is clicked, the button displays the number of seconds, and the display increases by 1 every second. Below is the first version

package com.albert.frame;

import java.awt.BorderLayout;

public class TestSwing extends JFrame {
	private JPanel contentPane;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TestSwing frame = new TestSwing();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace ();
				}
			}
		});
	}

	public TestSwing() {
		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);
		
		final JButton button = new JButton("点击");
		contentPane.add(button, BorderLayout.CENTER);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
an				for(int i=0;i<=5;i++){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					button.setText(i+"");
				}
			}
		});
	}

}

 After running the code and clicking the button, you will find that the interface is stuck, and after 5 seconds, 5 is displayed directly on the button. Instead of starting from 0 and incrementing by 1 every second as we would expect.

 

      Is this the reason above? Obviously this violates the above principle: time-consuming operations cannot be performed in the EDT thread. Because your time-consuming operation occupies the EDT thread, then the interface update will be queued after the time-consuming operation, and finally the interface update of the same component will be merged into the last one, which is directly displayed 5. It should be noted that the various event monitoring methods of the Swing component are called in the EDT thread, such as the click event.

 

      Since the program is not executed according to our ideas, because it violates the principle of GUI single thread, then we modify the program again, add the time-consuming operation code to a separate thread, and only post the modified part

button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				new Thread(new Runnable() {
					public void run() {
						for(int i=0;i<=5;i++){
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e1) {
								e1.printStackTrace();
							}
							button.setText(i+"");
						}
					}
				}).start();
			}
		});
}

 

 

Run the program and click the button, and find that the program executes as we expect. Are you very happy, but don't be too happy too early, although the function is realized, it still violates the GUI single-threaded principle: the interface is updated in the EDT thread. And we run the code for this interface update operation in a separate thread: button.setText(i+"").

       It's a big head, button.setText() and our time-consuming operation are a code block, how can they be executed in two threads separately? It's a dog day! ! In fact, Swing provides us with a tool class SwingUtilities, which has a method invokeLater(Runnable runnable). There is an interface declared by the run method) to the EDT thread for execution by the EDT thread. Modify the code again

button.addActionListener(new ActionListener() {
			int i;
			public void actionPerformed(ActionEvent e) {
				new Thread(new Runnable() {
					public void run() {
						for(i=0;i<5;i++){
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e1) {
								e1.printStackTrace();
							}
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									button.setText(i+"");
								}
							});
						}
					}
				}).start();
			}
		});
	}

 The result of program execution is what we expect, and it also conforms to the principle of GUI single thread, everyone is happy.

 Then introduce the class SwingWorker provided by Swing, perform time-consuming operations in doInbackground(), and then return the result. You can use get() in the done() method to get the result returned by doInbackground() to refresh the interface.

SwingWorker worker = new SwingWorker<Integer, Void>() {
				@Override
				protected Integer doInBackground() throws Exception {
					// Time-consuming operation. . .
					
					return 0;
				}
				@Override
				protected void done() {
					super.done();
					//After the above time-consuming operation is completed, give done() to EDT for execution.
				}
			};

 

Well, the above is the thread description of Swing, I hope it helps

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326222805&siteId=291194637