Every thread in the JVM is represented by a Java object of class
Thread
.
A snippet of the class java.lang.thread:
package java.lang; public class Thread implements Runnable { public final static int MIN_PRIORITY = 1; public final static int NORM_PRIORITY = 5; public final static int MAX_PRIORITY = 10; public Thread() {...} public Thread(Runnable target) {...} public Thread(ThreadGroup group, Runnable target) {...} public Thread(String name) {...} public Thread(ThreadGroup group, String name) {...} public Thread(Runnable target, String name) {...} public Thread(ThreadGroup group, Runnable target, String name) {...} public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {...} public synchronized void start() {...} public void run() {...} public final void suspend() {...} public final void resume() {...} public void interrupt() {...} public static boolean interrupted() {...} public boolean isInterrupted() {...} public final void stop() {...} public void destroy() {...} public final native boolean isAlive(); public final String getName() {...} public final void setName(String name) {...} public final int getPriority() {...} public final void setPriority(int newPriority) {...} public final boolean isDaemon() {...} public final void setDaemon(boolean on) {...} public final ThreadGroup getThreadGroup() {...} public ClassLoader getContextClassLoader() {...} public enum State {NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED} public State getState() {...} public long getId() {...} public static int activeCount() {...} public static int enumerate(Thread tarray[]) {...} public static native boolean holdsLock(Object obj); public static native Thread currentThread(); public static native void yield(); public static native void sleep(long millis) throws InterruptedException; public static void sleep(long millis, int nanos) throws InterruptedException {...} public final synchronized void join(long millis) {...} public final synchronized void join(long millis, int nanos) {...} public final void join() {...} public static void dumpStack() {...} public StackTraceElement[] getStackTrace() {...} public static Map<Thread, StackTraceElement[]> getAllStackTraces() {...} public native int countStackFrames(); public final void checkAccess() {...} . . . public interface UncaughtExceptionHandler {...} public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {...} public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {...} public UncaughtExceptionHandler getUncaughtExceptionHandler() {...} public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {...} }
The most important properties of a thread are:
run()
method is run on the threadWhen the JVM starts, there are four threads running (and two thread groups to house them):
Object.wait
.Exercise: Draw a state diagram for a Java thread, using the six states above. You'll have to do some research to get the transitions (and their triggers) just right.
Of interest:
Every thread has a runnable object that it runs. A runnable is anything implementing this interface:
package java.lang; public interface Runnable { void run(); }
Usually the runnable is passed to the thread's constructor.
To start the thread, call
the thread's start
method. Don't call the run()
method directly! If you do, it will run on the caller's thread
(just like any normal method), which likely isn't what you
want. Calling Thread.start()
is the only way
to spawn a new thread.
class Worker implements Runnable { ... public void run() {...} } ... Worker w = new Worker(); Thread t = new Thread(w); t.start();
There's a cool shortcut you can use because Thread implements Runnable:
class Worker extends Thread { ... public void run() {...} } Worker w = new Worker(); w.start();
If you want to be really compact, subclass Thread with an anonymous class:
Thread t = new Thread() { ... public void run() {...} }; t.start();
or even
(new Thread() { ... public void run() {...} }).start();
But since Java only allows single inheritance, you can't use this shortcut if your runnable already extends another class. A common idiom is to stick a thread inside the runnable object:
class Worker extends Generator implements Runnable { ... private Thread thread; public void run() {...} public void start() { thread = new Thread(this); thread.start(); }
A thread stops running when
run
method completes, orRuntime.exit()
is called and the security manager allows
the call, or (2) all non-daemon threads have terminated.How do you forcibly stop a thread? Answer: periodically examine a flag.
class Worker extends Thread { private volatile boolean readyToStop = false; public void finish() {readyToStop = true;} public void run() { while (!readyToStop) { ... } } ... }
class Worker implements Runnable { private volatile Thread thread = new Thread(this); public void finish() {thread = null;} public void run() { while (thread == currentThread()) { ... } } ... }
Do not call the deprecated stop() method. It is unsafe. It causes the thread to abort no matter what it's doing, and it could be in the middle of executing a critical section with data in an inconsistent state. See the article explaining the deprecation of Thread.stop, Thread.suspend and Thread.resume.
Normally you'd want to wrap the body of the run() method in a try-finally block to make sure you clean up in case an exception was thrown. If you wanted to react to an exception you'd need catch-clauses as well. All run() methods would have to be structured this way.
An alternative is to install an UncaughtExceptionHandler for a thread or thread group. Or set the application-wide default uncaught exception handler. This example should explain it all:
/** * An application illustrating the use of uncaught exception handlers. Remember * if an uncaught exception is thrown in a thread, the system first tries the * thread's uncaught exception handler; if that is missing it tries the thread's * thread group's handler; if that fails it tries the default uncaught exception * handler. */ public class UncaughtExceptionDemo { private ThreadGroup group1 = new ThreadGroup("group1") { public void uncaughtException(Thread t, Throwable x) { System.out.println(t.getName() + " deferred to its group to " + "handle uncaught exception: " + x); } }; private Thread thread1 = new Thread(group1, "thread1") { { setUncaughtExceptionHandler(new UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable x) { System.out.println(t.getName() + " handled its own " + "uncaught exception: " + x); } }); } public void run() { throw new RuntimeException(); } }; private Thread thread2 = new Thread(group1, "thread2") { public void run() { throw new RuntimeException(); } }; private Thread thread3 = new Thread("thread3") { public void run() { throw new RuntimeException(); } }; public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable x) { System.out.println(t.getName() + " invoked the default " + "handler for uncaught exception: " + x); } }); UncaughtExceptionDemo demo = new UncaughtExceptionDemo(); demo.thread1.start(); demo.thread2.start(); demo.thread3.start(); } }
Output:
thread2 deferred to its group to handle uncaught exception: java.lang.RuntimeException thread1 handled its own uncaught exception: java.lang.RuntimeException thread3 invoked the default handler for uncaught exception: java.lang.RuntimeException
In general getting actions in a multithreaded program to happen in some correct order is hard because
Thread-1 Thread-2 ---------- ----------- 1: r2 = A 3: r1 = B 2: B = 1 4: A = 2 Initially A == B == 0, but it's possible to get r2 == 2 and r1 == 1; a compiler can reorder the instructions in any thread.
The JLS formally specificies a memory model and defines kinds of actions (read, write, synchronization, external, and thread divergence) so as to formally define a orderings of actions that help (see Section 17.4 of the specification).
While there are many details, the most useful things to know are:
Java developers have a lot of choices for synchronizing:
There are also things that look like synchronization but are not: priorities, sleeping, yielding, and timers.
Every object has a monitor which can be locked an unlocked. The monitor can only be owned by one thread at a time. If the monitor is owned by t1 and a different thread t2 wants it, t2 blocks. When the monitor gets unlocked, the threads blocked on the monitor compete for it and only one of them gets it.
The monitor for object o is only acquired by executing a synchronized statement on o:
synchronized (o) { ... }
The lock is freed at the end of the statment (whether it completes normally or via an exception).
You can mark methods synchronized
class C { synchronized void p() {...} static synchronized void q() {...} ... }
but this is just syntactic sugar for
class C { void p() {synchronized (this) {...}} static void q() {synchronized(C.class) {...}} ... }
The synchronized statement is used to enforce mutual exclusion. When multiple threads access the same piece of data, it's imperative that one thread not see the data in an intermediate state. Example:
class PriorityQueue { // Implemented as a binary heap private Object[] data; private int size; ... public synchronized add(Object o) { if (size == data.length) { throw new HeapFullException(); } data[size++] = o; siftUp(); } public synchronized Object remove() { ... } public synchronized String toString() { ... } }
If the methods add() and remove() are not synchronized several problems could occur.
Note: In the above example all methods have to be synchronized. If add() is synchronized and remove() is not, they can still both be running at the same time!
You might be able to avoid locking the object and still
have mutual exclusion in the case in which the
shared data is a single field.
This is because Java guarantees loading and storing of
variables (except longs and doubles) are atomic — there's
no "intermediate state" during a store nor can it be changed
in the middle of a load. (Note only loads and stores
are atomic, an expression like x++
is not.)
HOWEVER, threads can hold variables in registers. If a shared
variable is in a register one thread won't be able to see
another thread's change to it. The volatile
keyword
is there to prevent that. The Java Language Specification
states that "A field may be declared volatile, in which case the Java memory
model ensures that all threads see a consistent value for the variable."
One policy that an implementation may take is that for fields marked volatile,
- All reads must come from main memory
- All writes must go to main memory
A volatile field can let you avoid a synchronized statement and the associated lock contention. (This works for longs and doubles, too — marking them volatile not only ensures threads see consistent updates but it forces atomicity where none existed before: see the JLS, section 17.7.)
If your synchronization requirements are very complex, explicit locks might be more convenient. Read the Javadocs for the package java.util.concurrent.locks; they are extensive and quite decent.
Rule #1: unlock the lock in a finally block!
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
Lock l = ...; if (l.trylock()) { // Got it try {...} finally {l.unlock();} } else { // Didn't get it right away, do something else ... }
Lock l = ...; if (l.trylock(3000, TimeUnit.MILLISECONDS)) { // Got it try {...} finally {l.unlock();} } else { // Didn't get it within 3 seconds, do something else ... }
The Java Core API provides one class for single-owner locks [Javadocs]:
package java.util.concurrent.locks; public class ReentrantLock implements Lock, java.io.Serializable { public ReentrantLock() {...} public ReentrantLock(boolean fair) {...} public void lock() {...} public void lockInterruptibly() throws InterruptedException {...} public boolean tryLock() {...} public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {...} public void unlock() {...} public Condition newCondition() {...} public int getHoldCount() {...} public boolean isHeldByCurrentThread() {...} public boolean isLocked() {...} public final boolean isFair() {...} protected Thread getOwner() {...} public final boolean hasQueuedThreads() {...} public final boolean hasQueuedThread(Thread thread) {...} public final int getQueueLength() {...} protected Collection<Thread> getQueuedThreads() {...} public boolean hasWaiters(Condition condition) {...} public int getWaitQueueLength(Condition condition) {...} protected Collection<Thread> getWaitingThreads(Condition condition) {...} public String toString() {...} }
In this class
fair
in the constructor means
waiters are queued FIFO. It doesn't mean anything else.
For example another thread executing tryLock()
might jump ahead of all waiters.A ReadWriteLock [Javadocs] contains a pair of locks: one exlusive write lock and one non-exclusive read lock.
package java.util.concurrent.locks; public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }
Implicit Locks | Explicit Locks |
---|---|
|
|
A common synchronization issue arises when you have to modify a shared resource only if some condition holds. But you need the object lock to combine the check and update. However if the condition does not hold you want to block until it does. But you can't wait for the condition while holding the lock, so there's some built-in support for all this.
There are ways to do this with both implicit and explicit locks
The most straightforward way to implement this in Java
is to use the wait
and notify
methods
of the class Object
. Here's an implementation
of a blocking queue:
public class BlockingQueue { private Object[] data; private int head = 0; private int tail = 0; private int count = 0; public Buffer(int capacity) { data = new Object[capacity]; } public synchronized void add(Object item) throws InterruptedException { while (count == data.length) {wait();} data[tail] = item; tail = (tail + 1) % data.length; count++; notifyAll(); } public synchronized Object remove() throws InterruptedException { while (count == 0) {wait();} Object item = data[head]; head = (head + 1) % data.length; count--; notifyAll(); return item; } public synchronized int getSize() { return count; } }
See the JLS for the semantics of wait and notify, or see the Javadocs for class Object for a slightly less formal treatment. The high-level explanation is:
Condition objects [Javadocs] give wait and notify functionality to explicit locks the same way wait() and notify() work with implicit locks. This gives us a situation where the add threads and the remove threads are in separate wait sets!. Example:
class BlockingQueue { private final Lock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); private final Object[] data; private int head = 0; private int tail = 0; private int count = 0; public void add(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); data[tail] = item; tail = (tail + 1) % data.length; count++; notEmpty.signal(); } finally { lock.unlock(); } } public Object remove() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object item = data[head]; head = (head + 1) % data.length; count--; notFull.signal(); return item; } finally { lock.unlock(); } } }
Good to know
There are some cool little things you can use in place of locks and conditions. Most are objects that hand out "permits" — a thread blocks until a permit is available.
Threads wait on a countdown latch until the count goes down to zero. Then they pass.
package java.util.concurrent; public class CountDownLatch { public CountDownLatch(int count) {...} public void await() throws InterruptedException {...} public boolean await(long timeout, TimeUnit unit) throws InterruptedException {...} public void countDown() {...} public long getCount() {...} // just for debugging and testing public String toString() {...} }
The details
For examples of use, see the Javadocs.
A number of threads meet (block) at the barrier, and when the last thread in the party arrives, they are all released. The barrier object can be reused after the threads have been released.
package java.util.concurrent; public class CyclicBarrier { public CyclicBarrier(int parties, Runnable barrierAction) {...} public CyclicBarrier(int parties) {...} public int getParties() {...} public int await() throws InterruptedException, BrokenBarrierException {...} public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException {...} public boolean isBroken() {...} public void reset() {...} public int getNumberWaiting() {...} // just for debugging }
Notes
For examples of use, see the Javadocs.
An exchanger is used as a synchronization point at which two threads can exchange objects. Each thread presents some object on entry to the exchange method, and receives the object presented by the other thread on return.
package java.util.concurrent; public class Exchanger<V> { private final ReentrantLock lock = new ReentrantLock(); private final Condition taken = lock.newCondition(); private V item; . . . public Exchanger() {...} public V exchange(V x) throws InterruptedException {...} public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {...} }
Good to know
For examples of use, see the Javadocs.
A semaphore maintains a counter of available permits; threads can block on a semaphore until there's a permit available. There are ways to acquire conditionally, interruptibly, or subject to a time out.
package java.util.concurrent; public class Semaphore implements java.io.Serializable { public Semaphore(int permits) {...} public Semaphore(int permits, boolean fair) {...} public void acquire() throws InterruptedException {...} public void acquireUninterruptibly() {...} public boolean tryAcquire() {...} public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {...} public void release() {...} public void acquire(int permits) throws InterruptedException {...} public void acquireUninterruptibly(int permits) {...} public boolean tryAcquire(int permits) {...} public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {...} public void release(int permits) {...} public int availablePermits() {...} public int drainPermits() {...} // acquire and return them all, return num acquired protected void reducePermits(int reduction) {...} // this does not block public boolean isFair() {...} public final boolean hasQueuedThreads() {...} // don't rely on it public final int getQueueLength() {...} // just an estimate; don't rely on it protected Collection<Thread> getQueuedThreads() {...} // just an estimate; don't rely on it public String toString() {...} }
Good to know:
For examples of use, see the Javadocs.
The package java.util.concurrent.atomic [Javadocs] has a bunch of classes to make accessing single variables thread-safe without using locks. (Native methods are used instead.)
The classes
Good to know
class Sequencer { private AtomicLong sequenceNumber = new AtomicLong(0); public long next() { return sequenceNumber.getAndIncrement(); } }
Thread t1 can call t2.interrupt() to interrupt t2 from blocking on something:
If t is blocking on... | Then t.interrupt() ... | and t's interrupt status gets set to... |
---|---|---|
Object.wait Thread.join Thread.sleep |
completes the blocking call and makes t get an InterruptedException | false |
an I/O operation on an interruptable channel | closes the channel and makes t get a ClosedByInterruptException | true |
a selector | completes the call (just like wakeup) | true |
nothing | does nothing | true |
A thread can voluntarily
Thread.sleep
)Thread.yield
)But what if we want one thread to force another thread to suspend execution?
First, don't use the suspend()
method!
It's deprecated. (Threads keep their monitor locks when they go
to sleep and this is very deadlock prone — the thread that's
supposed to call resume just might try to get that very same lock!)
See the
article
explaining the deprecation of Thread.stop, Thread.suspend and Thread.resume.)
If you want to forcibly suspend some other thread, write the other
thread to periodically see if it should be suspended and voluntarily
block on a condition until woken up.
class Worker implements Runnable { private volatile boolean shouldBeSuspended = false; public void run() { while (true) { ... try { if (shouldBeSuspended) { synchronized (this) { while (shouldBeSuspended) wait(); } } catch (InterruptedException ignored) { } ... } } public void suspend() { shouldBeSuspended = true; } public synchronized void resume() { shouldBeSuspended = false; notify(); } ... }
You can get some of this functionality with LockSupport.park and LockSupport.unpark [Javadocs].
public class LockSupport { private LockSupport() {} // Cannot be instantiated. public static void park() {...} public static void parkNanos(long nanos) {...} public static void parkUntil(long deadline) {...} public static void unpark(Thread thread) {...} }
Good to know
The Javadocs have a good example of how to implement a FIFO Mutex with the LockSupport methods.
You should read Brian Goetz's article on ThreadLocals. It's better than anything I could write.
run()
method?Most of the time when threads share data, they're not just sharing a single variable. And as you know, updating a collection is rarely an atomic operation. There's lots of potential for races; there's also the potential for writing inefficient code with too much locking.
Java has a relatively huge API for collections. To get started, see my notes on collections These notes feature links to Sun's documentation and tutorial articles. I've also included there a table of cocurrency properties for each of the collection classes.
A summary of important points
Graphics-intensive code pretty much requires threading: GUI programs are event-driven, and event handling and painting need to happen on a separate thread from your computations lets your computations prevent repainting. Of course, this means if you run code on this thread, it better not take too long.
Rule 1: All operations on the GUI thread should be short.
The interesting thing, though, is that the GUI components in Java's Swing Library (e.g. buttons, sliders, progress bars, dialogs, windows, scrollpanes, etc.) are not threadsafe. Updates you make on a "worker thread" will conflict with those made on the "event handling thread." (It doesn't matter if you enclose your worker code in a synchronized block — the internal component management code in Swing won't care!) Therefore:
Rule 2: Operate on Swing components only on the GUI thread.
After all, that's the general way to deal with thread-unsafe objects.
Wait! Don't know much about Swing, or about graphics in general? Check out
Here's a little application that shows what kind of operations are performed on which threads:
import java.awt.Image; import java.awt.Toolkit; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.ImageObserver; import javax.swing.JFrame; import javax.swing.SwingUtilities; /** * A small application that shows which threads execute particular operations, * in particular: * <ul> * <li>plain operations on the main thread</li> * <li>mouse event handlers</li> * <li>image loading observing</li> * <li>operations passed to SwingUtilities.invokeLater</li> * <li>operations passed to an anonymous thread</li> * </ul> */ public class GUIThreadDemo { public static void main(String[] args) { JFrame frame = new JFrame("Click in the window to exit"); frame.setSize(600, 240); frame.setVisible(true); // What thread handles mouse events? frame.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println("MouseEvent handled in " + Thread.currentThread()); System.exit(0); } }); // What thread does main() run on? System.out.println("main() runs in " + Thread.currentThread()); // What about anonymous threads? (new Thread() { public void run() { System.out.println("This thread is " + Thread.currentThread()); } }).start(); // What thread does invokeLater run on? SwingUtilities.invokeLater(new Runnable() { public void run() { System.out.println("SwingUtilities.invokeLater() runs on " + Thread.currentThread()); } }); // What thread are images loaded on? Image image = Toolkit.getDefaultToolkit() .getImage(GUIThreadDemo.class.getClassLoader().getResource("face.gif")); frame.getContentPane().getGraphics().drawImage(image, 0, 0, new ImageObserver() { public boolean imageUpdate(Image i, int flags, int x, int y, int width, int height) { if ((flags & ALLBITS) != 0) { System.out.println("Image loaded in " + Thread.currentThread()); return false; } return true; } }); } }
On my box it outputs
main() runs in Thread[main,5,main] This thread is Thread[Thread-2,5,main] SwingUtilities.invokeLater() runs on Thread[AWT-EventQueue-0,6,main] Image loaded in Thread[Image Fetcher 0,3,main] MouseEvent handled in Thread[AWT-EventQueue-0,6,main]
TODO - example of blocking the GUI thread for a long time. The idea is to have a frame with two buttons, a text area, and a message area. The buttons simulate a 30 second server request. One button does the request on the GUI thread to illustrate the event thread lock up. The other does the request on another thread showing that you can still type in the text area.
TODO (maybe) - example of a race condition when updating a Swing component on the worker thread
Of interest to thread-conscious Swing developers is the SwingUtilities class are:
SwingUtilities.invokeLater SwingUtilities.invokeAndWait SwingUtilities.isEventDispathThread
All these methods do is call the same-named methods in EventQueue. The implementation of these methods are interesting:
package awt; public class EventQueue { . . . public static void invokeLater(Runnable runnable) { Toolkit.getEventQueue().postEvent( new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); } public static void invokeAndWait(Runnable runnable) throws InterruptedException, InvocationTargetException { if (EventQueue.isDispatchThread()) { throw new Error("Cannot call invokeAndWait from the event dispatcher thread"); } class AWTInvocationLock {} Object lock = new AWTInvocationLock(); InvocationEvent event = new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, true); synchronized (lock) { Toolkit.getEventQueue().postEvent(event); lock.wait(); } Throwable eventThrowable = event.getThrowable(); if (eventThrowable != null) { throw new InvocationTargetException(eventThrowable); } } public static boolean isDispatchThread() { EventQueue eq = Toolkit.getEventQueue(); EventQueue next = eq.nextQueue; while (next != null) { eq = next; next = eq.nextQueue; } return (Thread.currentThread() == eq.dispatchThread); } }
As you can probably imagine, the InvocationEvent looks like:
package java.awt.event; public class InvocationEvent extends AWTEvent implements ActiveEvent { public InvocationEvent(Object source, Runnable runnable) {....} public InvocationEvent(Object source, Runnable runnable, Object notifier, boolean catchThrowables) {....} public void dispatch() { if (catchExceptions) { try { runnable.run(); } catch (Throwable t) { if (t instanceof Exception) { exception = (Exception) t; } throwable = t; } } else { runnable.run(); } if (notifier != null) { synchronized (notifier) { notifier.notifyAll(); } } } public Exception getException() {...} public Throwable getThrowable() {...} . . . }
There's an interesting class called SwingWorker that isn't part of the Java Core API. Sun just posted its source to the web. It lets you execute a time-consuming task on a worker thread and after that worker is finished you can do a little something on the GUI thread:
import javax.swing.SwingUtilities; public abstract class SwingWorker { private Object value; /** * Class to maintain reference to current worker thread * under separate synchronization control. */ private static class ThreadVar { private Thread thread; ThreadVar(Thread t) { thread = t; } synchronized Thread get() { return thread; } synchronized void clear() { thread = null; } } private ThreadVar threadVar; protected synchronized Object getValue() { return value; } private synchronized void setValue(Object x) { value = x; } // Override construct() and perhaps finished() in your subclass public abstract Object construct(); public void finished() {} public void interrupt() { Thread t = threadVar.get(); if (t != null) { t.interrupt(); } threadVar.clear(); } /** * Return the value created by theconstruct
method. * Returns null if either the constructing thread or the current * thread was interrupted before a value was produced. * * @return the value created by theconstruct
method */ public Object get() { while (true) { Thread t = threadVar.get(); if (t == null) { return getValue(); } try { t.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // propagate return null; } } } /** * Start a thread that will call theconstruct
method * and then exit. */ public SwingWorker() { final Runnable doFinished = new Runnable() { public void run() { finished(); } }; Runnable doConstruct = new Runnable() { public void run() { try { setValue(construct()); } finally { threadVar.clear(); } SwingUtilities.invokeLater(doFinished); } }; Thread t = new Thread(doConstruct); threadVar = new ThreadVar(t); } /** * Start the worker thread. */ public void start() { Thread t = threadVar.get(); if (t != null) { t.start(); } } }
To use
private Action saveAction = new AbstractAction("Save") { public void actionPerformed(ActionEvent e) { final SwingWorker worker = new SwingWorker() { // define fields here if you need them public Object construct() { // contact a server or do a serious calculation // return something if necessary } public void finished() { // Update GUI } }; worker.start(); } }
Threads are important (actually, required) when you need to run certain jobs at certain times, or periodically, or until certain times, etc.
Understand the difference between the different uses of scheduling:
Every Java thread has a priority between 0 and 10. The priority
is initally that of the thread that created it. You can call
setPriority()
to change it; the JVM will never change
it on its own.
The JVM uses a preemptive, priority-based scheduler. When it is time to pick a thread to run, the scheduler picks
the highest priority thread that is currently runnable
and
when a thread gets moved into the runnable state and the currently executing thread as strictly lower priority, the higher priority thread preempts the running thread
and
among threads of the same priority, round-robin scheduling is used.
BUT these are only guidelines, or hints, provided to the operating systems. The operating system makes the ultimate scheduling choices. In other words, the priority within the JVM is not the same as the priority of the thread assigned by the operating system!! Don't even expect it to be. The O.S. can give boosts; the JVM will not. So you can never rely on priorites for synchronization, ordering of operations, or race condition prevention.
An example of how things might work:
Generally you should not care about this stuff, but if you have a platform that you know is not timesliced and you have a CPU-intensive thread, you might want to give this thread a priority less than the GUI thread. Do you see why?
And in general, threads that block a lot should get a higher priority than those that are CPU-intensive. Do you see why?
A thread pool is a fixed collection of threads that you submit tasks to. A thread in the pool generally wakes up to run a task, then goes back to idling.
By task we mean either a Runnable or a Callable
package java.lang; public class Runnable { void run(); }
package java.util.concurrent; public interface Callable<V> { V call() throws Exception; }
What good are thread pools?
But don't use thread pools when
An executor is something that runs a task
package java.util.concurrent; public interface Executor { void execute(Runnable command); }
There's a simple executor interface, called an ExecutorService [Javadocs]:
package java.util.concurrent; public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future< submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<Callable<T>> tasks) throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
and an executor which extends the simple ExecutorService with the ability to schedule tasks [Javadocs]:
package java.util.concurrent; public interface ScheduledExecutorService extends ExecutorService { ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); }
Here is a pretty cool example that uses a simple thread pool (not how the thread pool is returned from a static factory method in the Executors class). The example is very simple; it only calls execute, not submit, and cares not at all about what "results" the tasks are computing (there are none), nor does it care about termination.
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; /** * A simple Swing application that serves as a demostration of graphics and * thread pools. A user can launch bouncing balls by clicking on a button. Each * ball is run on a thread and these threads come from a fixed-size thread pool. * Each ball lives for a limited but not too short of a time, so repeatedly * clicking the launch button can cause the pool to fill up and require new * balls to wait. * * The main frame window includes a status line with information about the * application's state. */ public class ThreadPoolBouncer extends JFrame implements Runnable { private Random random = new Random(); private static final int POOL_SIZE = 8; private JPanel canvas = new JPanel(); private JLabel statusLabel = new JLabel(); private int activeCount = 0; private int waitCount = 0; /** * A thread to do the rendering on, since we don't want to render on the user * interface thread. */ private Thread renderThread = new Thread(this); /** * Stores all the ball tasks. Note balls are not threads -- they are runnables * which will be run on threads from a thread pool. */ private List<Ball> balls = Collections.synchronizedList(new ArrayList<Ball>()); private ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE); /** * An action to launch a new ball. */ private Action launchAction = new AbstractAction("Launch") { public void actionPerformed(ActionEvent e) { Ball ball = new Ball(); balls.add(ball); synchronized (this) { waitCount++; updateStatus(); } pool.execute(ball); } }; /** * Constructs and lays out the application frame. */ public ThreadPoolBouncer() { JPanel statusPanel = new JPanel(); statusPanel.add(new JButton(launchAction)); statusPanel.add(statusLabel); getContentPane().add(statusPanel, BorderLayout.SOUTH); getContentPane().add(canvas, BorderLayout.CENTER); setResizable(false); } /** * Renders the canvas with all the balls. First it creates a back buffer and * graphics objects for the back buffer and the canvas. Then it loops around * drawing all the live balls to the back buffer then blitting the back buffer * to the canvas. */ public void run() { Image buffer = createImage(canvas.getWidth(), canvas.getHeight()); Graphics g = buffer.getGraphics(); Graphics gc = canvas.getGraphics(); while (true) { g.setColor(Color.white); g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); synchronized (balls) { for (Ball b : balls) { b.draw(g); } } gc.drawImage(buffer, 0, 0, canvas); try { Thread.sleep(5); } catch (InterruptedException e) { } } } private void updateStatus() { final String text; synchronized (this) { text = "Waiting: " + waitCount + " Active: " + activeCount; } SwingUtilities.invokeLater(new Runnable() { public void run() { statusLabel.setText(text); } }); } /** * Runs the demonstration as an application. */ public static void main(String[] args) { ThreadPoolBouncer bouncer = new ThreadPoolBouncer(); bouncer.setTitle("Bouncing Balls"); bouncer.setSize(800, 600); bouncer.setVisible(true); bouncer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); bouncer.renderThread.setPriority(Thread.MAX_PRIORITY); bouncer.renderThread.start(); } /** * A ball is something that bounces around on a JPanel. Balls are created with a * random color not too close to white, initially at a random position on the * canvas and oriented in an random direction (neither horizontal or vertical). */ private class Ball implements Runnable { private Color color = new Color(random.nextInt(200), random.nextInt(200), random.nextInt(255)); private int x = random.nextInt(getWidth()); private int y = random.nextInt(getWidth()); private int dx = 1 + random.nextInt(5); private int dy = 1 + random.nextInt(3); private static final int RADIUS = 10; /** * Draws the ball as a filled in circle. */ public void draw(Graphics g) { g.setColor(color); g.fillOval(x, y, RADIUS, RADIUS); } /** * Updates the position of the ball, taking care of bounces. */ protected void move() { x += dx; y += dy; if (x < 0) { // Bounce off left wall. x = 0; dx = -dx; } if (x + RADIUS >= canvas.getWidth()) { // Bounce off right wall. x = canvas.getWidth() - RADIUS; dx = -dx; } if (y < 0) { // Bounce off top wall. y = 0; dy = -dy; } if (y + RADIUS >= canvas.getHeight()) { // Bounce off bottom wall. y = canvas.getHeight() - RADIUS; dy = -dy; } } /** * A ball basically just moves 1000 times. After each position update, it sleeps * for 5 milliseconds. */ public void run() { synchronized (this) { waitCount--; activeCount++; updateStatus(); } for (int i = 1; i <= 1000; i++) { move(); try { Thread.sleep(5); } catch (InterruptedException e) { } } balls.remove(this); synchronized (this) { activeCount--; updateStatus(); } } } }
You will need to instantiate a concrete class to actually use a thread pool. The simple ThreadPoolExecutor implements the ExecutorService
TODO
The ScheduledThreadPoolExecutor extends the ScheduledExecutorService:
TODO
If you don't need sophisticated control over the thread pool, there are static factory methods in the utility class Executors you can use.
TODO
If you have very simple scheduling needs, you can use a simple timer in place
of a scheduled thread pool executor. The Timer
class in java.util
looks like:
The swing timer class is even simpler and less flexible than the util timer, but it's there to make it easy to execute actions on the GUI threads. Swing timers aren't very generic: they only support one "schedule".
TODO