swing與執行緒
swing與執行緒:
1.如果一個動作需要花費很長時間,在一個獨立的工作執行緒中坐這個事情,不要在事件分配執行緒中做。
意思是可以在事件分配的執行緒中另起一個執行緒做這個事情。
2.除了事件分配執行緒,不要再任何執行緒中接觸swing元件。
如果一個耗時的任務,在過程中要更新GUI上的進度顯示。但是由於這個耗時的工作執行緒不能接觸GUI,如何解決?
可以使用EventQueue類的invokeLater(),和invokeAndWait()中實行。
這兩個方法的區別是invokeLater()會立即返回,而invokeAndWait()會等待執行完之後返回。
e.g:下面的示範,如果接連按good按鈕程式不會出現異常,但是接連按bad按鈕會出現異常。
package v1ch14.SwingThreadTest;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
/**
* This program demonstrates that a thread that runs in parallel with the event dispatch thread can
* cause errors in Swing components.
* @version 1.23 2007-05-17
* @author Cay Horstmann
*/
public class SwingThreadTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
SwingThreadFrame frame = new SwingThreadFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame has two buttons to fill a combo box from a separate thread. The "Good" button uses the
* event queue, the "Bad" button modifies the combo box directly.
*/
class SwingThreadFrame extends JFrame
{
public SwingThreadFrame()
{
setTitle("SwingThreadTest");
final JComboBox combo = new JComboBox();
combo.insertItemAt(Integer.MAX_VALUE, 0);
combo.setPrototypeDisplayValue("set...");
combo.setSelectedIndex(0);
JPanel panel = new JPanel();
JButton goodButton = new JButton("Good");
goodButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
new Thread(new GoodWorkerRunnable(combo)).start();
}
});
panel.add(goodButton);
JButton badButton = new JButton("Bad");
badButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
new Thread(new BadWorkerRunnable(combo)).start();
}
});
panel.add(badButton);
panel.add(combo);
add(panel);
pack();
}
}
/**
* This runnable modifies a combo box by randomly adding and removing numbers. This can result in
* errors because the combo box methods are not synchronized and both the worker thread and the
* event dispatch thread access the combo box.
*/
class BadWorkerRunnable implements Runnable
{
public BadWorkerRunnable(JComboBox aCombo)
{
combo = aCombo;
generator = new Random();
}
public void run()
{
try
{
while (true)
{
int i = Math.abs(generator.nextInt());
if (i % 2 == 0) combo.insertItemAt(i, 0);
else if (combo.getItemCount() > 0) combo.removeItemAt(i % combo.getItemCount());
Thread.sleep(1);
}
}
catch (InterruptedException e)
{
}
}
private JComboBox combo;
private Random generator;
}
/**
* This runnable modifies a combo box by randomly adding and removing numbers. In order to ensure
* that the combo box is not corrupted, the editing operations are forwarded to the event dispatch
* thread.
*/
class GoodWorkerRunnable implements Runnable
{
public GoodWorkerRunnable(JComboBox aCombo)
{
combo = aCombo;
generator = new Random();
}
public void run()
{
try
{
while (true)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
int i = Math.abs(generator.nextInt());
if (i % 2 == 0) combo.insertItemAt(i, 0);
else if (combo.getItemCount() > 0) combo.removeItemAt(i
% combo.getItemCount());
}
});
Thread.sleep(1);
}
}
catch (InterruptedException e)
{
}
}
private JComboBox combo;
private Random generator;
}
在java6中,這樣的類已經寫進了類庫,就是swingWorker<T,V>類,T是工作器執行緒的返回值,V是想過程方法傳遞的引數。
e.g:
package v1ch14.SwingWorkerTest;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import javax.swing.*;
/**
* This program demonstrates a worker thread that runs a potentially time-consuming task.
* @version 1.1 2007-05-18
* @author Cay Horstmann
*/
public class SwingWorkerTest
{
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new SwingWorkerFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame has a text area to show the contents of a text file, a menu to open a file and cancel
* the opening process, and a status line to show the file loading progress.
*/
class SwingWorkerFrame extends JFrame
{
public SwingWorkerFrame()
{
chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
textArea = new JTextArea();
add(new JScrollPane(textArea));
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
statusLine = new JLabel(" ");
add(statusLine, BorderLayout.SOUTH);
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu menu = new JMenu("File");
menuBar.add(menu);
openItem = new JMenuItem("Open");
menu.add(openItem);
openItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
// show file chooser dialog
int result = chooser.showOpenDialog(null);
// if file selected, set it as icon of the label
if (result == JFileChooser.APPROVE_OPTION)
{
textArea.setText("");
openItem.setEnabled(false);
textReader = new TextReader(chooser.getSelectedFile());
textReader.execute();
cancelItem.setEnabled(true);
}
}
});
cancelItem = new JMenuItem("Cancel");
menu.add(cancelItem);
cancelItem.setEnabled(false);
cancelItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
textReader.cancel(true);
}
});
}
private class ProgressData
{
public int number;
public String line;
}
private class TextReader extends SwingWorker<StringBuilder, ProgressData>
{
public TextReader(File file)
{
this.file = file;
}
// the following method executes in the worker thread; it doesn't touch Swing components
@Override
public StringBuilder doInBackground() throws IOException, InterruptedException
{
int lineNumber = 0;
Scanner in = new Scanner(new FileInputStream(file));
while (in.hasNextLine())
{
String line = in.nextLine();
lineNumber++;
text.append(line);
text.append("\n");
ProgressData data = new ProgressData();
data.number = lineNumber;
data.line = line;
publish(data);
Thread.sleep(1); // to test cancellation; no need to do this in your programs
}
return text;
}
// the following methods execute in the event dispatch thread
@Override
public void process(List<ProgressData> data)
{ //事件執行緒也就是中間過程,這裡為什麼是list呢,因為publish方法的引數時可變陣列,而且由publish方法傳過來的資料可能不是同一個蘋率,所以當執行這個方法的時候可能publish已經執行了很多次,所以是list引數不是單個引數
if (isCancelled()) return;
StringBuilder b = new StringBuilder();
statusLine.setText("" + data.get(data.size() - 1).number);
for (ProgressData d : data)
{
b.append(d.line);
b.append("\n");
}
textArea.append(b.toString());
}
@Override
public void done()
{
try
{
StringBuilder result = get();//這裡得到的是doInBackground方法的返回的值,也就是工作器執行緒的返回值。
textArea.setText(result.toString()); //可以操作GUI
statusLine.setText("Done");
}
catch (InterruptedException ex)
{
}
catch (CancellationException ex)
{
textArea.setText("");
statusLine.setText("Cancelled");
}
catch (ExecutionException ex)
{
statusLine.setText("" + ex.getCause());
}
cancelItem.setEnabled(false);
openItem.setEnabled(true);
}
private File file;
private StringBuilder text = new StringBuilder();
};
private JFileChooser chooser;
private JTextArea textArea;
private JLabel statusLine;
private JMenuItem openItem;
private JMenuItem cancelItem;
private SwingWorker<StringBuilder, ProgressData> textReader;
public static final int DEFAULT_WIDTH = 450;
public static final int DEFAULT_HEIGHT = 350;
}
主要實現了上面的EventQueue類的invokeLater(),和invokeAndWait()的代替:
doInBackground()方法來實現後臺的工作執行緒。
process(List<V> data) 這一方法來處理分配執行緒中的中間進度資料。可在這裡實現對gui 的操作。
void publish(v... data)傳遞中間資料到事件執行緒。在工作執行緒中可以呼叫它
viod execute() 為工作器執行緒的執行預定這個工作器(啟動工作器執行緒)。
SwingWorker.StateValue getState得到這個工作器執行緒的狀態。
但是也有一些意外:
1。可以在任一個執行緒中新增或移除事件監聽器
2。有些Swing方法時執行緒安全的
JTextComponent.setText
JTextArea.insert
JTextArea.append
JTextArea.replaceRange
JComponent.repaint
JComponent.revalidate
Swing的設計者認為除了事件分配執行緒之外,從任何其它執行緒訪問元件永遠都是不安全的。因此你需要在事件分配執行緒中構建使用者介面。
相關文章
- Java開發中的執行緒安全選擇與Swing(轉)Java執行緒
- 執行緒與多執行緒執行緒
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- 執行緒、執行緒與程式、ULT與KLT執行緒
- Java Swing執行緒之SwingUtilities.invokeLater解釋Java執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- Java執行緒中斷與終止執行緒執行Java執行緒
- Java執行緒:執行緒的同步與鎖Java執行緒
- 程式與執行緒執行緒
- 執行緒與程式執行緒
- 執行緒與程序執行緒
- Java與執行緒Java執行緒
- 程序與執行緒執行緒
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- Android程式框架:執行緒與執行緒池Android框架執行緒
- Java多執行緒1:程式與執行緒概述Java執行緒
- 深入理解JVM(③)執行緒與Java的執行緒JVM執行緒Java
- 多執行緒與高併發(二)執行緒安全執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- Java執行緒(一):執行緒安全與不安全Java執行緒
- 聊聊執行緒技術與執行緒實現模型執行緒模型
- android程式與執行緒詳解二:執行緒Android執行緒
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- 執行緒與執行緒池的那些事之執行緒池篇(萬字長文)執行緒
- Java多執行緒學習(1)建立執行緒與執行緒的生命週期Java執行緒
- 程式設計思想之多執行緒與多程式(2):執行緒優先順序與執行緒安全程式設計執行緒
- GIL與多執行緒執行緒
- cpu、核與執行緒執行緒
- Notification與多執行緒執行緒
- 程式與執行緒--原理執行緒
- Java併發實戰一:執行緒與執行緒安全Java執行緒
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- 子執行緒與UI執行緒的通訊(委託)執行緒UI
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- 以生活例子說明單執行緒與多執行緒執行緒
- 26、多執行緒與並行執行緒並行
- 多執行緒-執行緒控制之休眠執行緒執行緒
- 多執行緒-執行緒控制之加入執行緒執行緒