📄 threadsexample.java
字号:
/** * This file contains two examples that demonstrate how to code a pair * of common threaded application idioms: using an interruptible worker * thread to compute a value, blocking a worker thread and prompting * a user for input with a modal dialog. * * setenv JAVA_HOME /usr/local/java/jdk1.1.5/solaris * setenv CLASSPATH /usr/local/java/swing-1.0.1/swing.jar:${JAVA_HOME}/lib/classes.zip * ${JAVA_HOME}/bin/javac ThreadsExample.java * ${JAVA_HOME}/bin/java -classpath .:${CLASSPATH} ThreadsExample */import java.awt.*;import java.awt.event.*;import java.io.*;import java.util.*;import com.sun.java.swing.*;import com.sun.java.swing.event.*;import com.sun.java.swing.text.*;import com.sun.java.swing.SwingUtilities;/** * An abstract class that you subclass to perform * GUI-related work in a dedicated thread. * For instructions on using this class, see * http://java.sun.com/products/jfc/swingdoc/threads.html * This version has an extra method called <code>interrupt()</code>, * see the Example1 class below for more information. */abstract class SwingWorker { private Object value; private Thread thread; /** * Compute the value to be returned by the <code>get</code> method. */ public abstract Object construct(); /** * Called on the event dispatching thread (not on the worker thread) * after the <code>construct</code> method has returned. */ public void finished() { } /** * A new method that interrupts the worker thread. Call this method * to force the worker to abort what it's doing. */ public void interrupt() { Thread t = thread; if (t != null) { t.interrupt(); } thread = null; } /** * Return the value created by the <code>construct</code> method. */ public Object get() { while (true) { // keep trying if we're interrupted Thread t; synchronized (SwingWorker.this) { t = thread; if (t == null) { return value; } } try { t.join(); } catch (InterruptedException e) { } } } /** * Start a thread that will call the <code>construct</code> method * and then exit. */ public SwingWorker() { final Runnable doFinished = new Runnable() { public void run() { finished(); } }; Runnable doConstruct = new Runnable() { public void run() { synchronized(SwingWorker.this) { value = construct(); thread = null; } SwingUtilities.invokeLater(doFinished); } }; thread = new Thread(doConstruct); thread.start(); }}/** * Loads the begin,end bracketed text from a file and creates * a tab pane for each one: * * @begin ExampleClassName ExampleTitle * Example HTML documentation * @end * * The Example1, Example2 classes are set up this way. */class ExampleContainer extends JTabbedPane{ class ExampleInfo { String className; String title; String htmlText; } static void messageAndExit(String msg) { System.err.println("\n" + msg); System.exit(1); } Reader makeHTMLDoc(String text) { String header = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\"><html><body>\n"; String footer = "</body>\n</html>\n"; return new CharArrayReader((header + text + footer).toCharArray()); } Vector parseExampleFile(File file) { /* Load the file into a string. We expand tabs here to work around * a bug in the HTML viewer. */ String fileContents = ""; try { DataInputStream stream = new DataInputStream(new FileInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer buffer = new StringBuffer(); int c; while((c = reader.read()) != -1) { if (c == '\t') { buffer.append(" "); } else { buffer.append((char)c); } } fileContents = buffer.toString(); } catch (IOException e) { messageAndExit("Couldn't load \"" + file + "\" " + e); } /* Extract the @begin,@end bracked text, create a ExampleInfo * object for each one. */ Vector rv = new Vector(); int i0 = 0; while ((i0 = fileContents.indexOf("\n@begin", i0)) != -1) { int i1 = fileContents.indexOf("@end", i0); if (i1 == -1) { messageAndExit("Can't find matching @end for " + fileContents.substring(i0)); } String s = fileContents.substring(i0 + "\n@begin".length() + 1, i1); StringTokenizer st = new StringTokenizer(s); ExampleInfo info = new ExampleInfo(); info.className = st.nextToken(" "); info.title = st.nextToken("\n").trim(); info.htmlText = st.nextToken(""); rv.addElement(info); i0 = i1; } return rv; } ExampleContainer(File file) { super(); Vector examples = parseExampleFile(file); for(int i = 0; i < examples.size(); i++) { ExampleInfo exampleInfo = (ExampleInfo)(examples.elementAt(i)); /* Create an instance of the example class */ Class exampleClass; Component exampleComponent; try { exampleClass = Class.forName(exampleInfo.className); exampleComponent = (Component)(exampleClass.newInstance()); } catch (Exception e) { exampleComponent = new JLabel("Can't build example: " + e); } /* Make a JEditorPane that Displays the HTML documentation * for the example. */ String header = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\"><html><body>\n"; String title = "<h1>" + exampleInfo.title + "</h1>\n"; String text = exampleInfo.htmlText + "\n"; String footer = "\n</body>\n</html>\n"; JEditorPane docView = new JEditorPane(); docView.setEditable(false); docView.setContentType("text/html"); Document doc = docView.getEditorKit().createDefaultDocument(); Reader inr = new CharArrayReader((header + title + text + footer).toCharArray()); try { docView.getEditorKit().read(inr, doc, 0); docView.setDocument(doc); } catch (Exception e) { messageAndExit("Couldn't parse HTML doc: " + e); } /* Add a tab that contains the example and its documentation */ JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(exampleComponent, BorderLayout.NORTH); panel.add(new JScrollPane(docView), BorderLayout.CENTER); panel.setPreferredSize(new Dimension(640, 480)); addTab(exampleInfo.className, panel); } }}/**@begin Example1 Interrupting a Swing Worker ThreadOne limitation of the SwingWorker class, defined in a previous issue of the Swing Connection,<A HREF="http://java.sun.com/products/jfc/swingdoc/threads.html">ThreadsThreads and Swing</A>, is that once a worker thread is started it can'tbe interrupted. It just runs until it's finished.Here's a simple example that demonstrates how one can use a slightly modified version of theSwingWorker class to support interrupting the worker thread.In this example we're performing a slow operation on a separate thread to avoid locking up the event dispatching thread, andthefore the entire GUI, while the operation is underway. In our examplewe're just using a loop that sleeps:<pre>for(int i = 0; i < progressBar.getMaximum(); i++) { updateStatus(i); Thread.sleep(500);}</pre>In this case <code>progressBar.getMaximum()</code> returns 100, so theloops takes nearly a minute to complete. In a real application you'dwant to take this approach if you were doing something that wascomputationally expensive, that might have to load a large number ofclasses, or that might block for network or disk IO, or have to wait forsome other resource. <p>To review: the SwingWorker class is a simple utility for computing a value on a new thread. To use it, one creates a subclass of SwingWorker thatoverrides the SwingWorker.construct() method to compute the value. For example this code fragment just spawns a thread that constructsa string, and then waits for the thread to finish:<pre>SwingWorker worker = new SwingWorker() { public Object construct() { return "Hello" + " " + "World"; }};System.out.println(worker.get().toString());</pre>The <code>SwingWorker.get()</code> method waits for the new thread to finish creating the value with the <code>SwingWorker.construct()</code> method. <p>As originally defined the SwingWorker class doesn't provide a way for an application to interrupt the new worker thread. It's rather bad stylefor an interactive application to make the user wait while a worker threadfinishes. If the user wants stop an operation that's in progress,the worker thread that's busy performing the operation should be interrupted as quickly as possible. To enable interrupting a SwingWorker we'll add onemethod:<pre>public void interrupt() { Thread t = thread; if (t != null) { t.interrupt(); } thread = null;}</pre>Note: the conditional statement that interrupts the thread isn't synchronizedbecause we're referring to a local variable <code>t</code>, not thethread field itself. To demonstrate the <code>SwingWorker.interrupt()</code> method we've created an application that allows one to start a SwingWorkerand then either wait for it to complete or interrupt it. The SwingWorkersconstruct method just calls a method called <code>doWork()</code> whichwas introduced earlier:<pre>Object doWork() { try { for(int i = 0; i < progressBar.getMaximum(); i++) { updateStatus(i); Thread.sleep(500);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -