Threads
Basic Idea
- Execute more than one piece of code at the "same time".
- If more than one CPU, true concurrency is possible.
- If only one CPU, use time slicing.
- Rotates CPU among threads / processes.
- Gives appearance of simutaneous execution.
- Very advantageous in several situations.
- Cost of switching is important.
- Doesn't improve CPU-bound task.
Threads vs Processes
Multiple processes / tasks
- Separate programs.
- Separate address spaces.
- High switching overhead
- Costly interprocess communication.
Threads
- Within one program.
- Shared address space
- May use same hardware cache
- May use same virtual memory.
- Shared heap.
- Separate stack for each thread.
- Lower switching overhead than processes.
- Easy communication with other threads.
Cooperative vs Pre-emptive
Cooperative multithreading
- A thread decides when to give up the CPU.
- It can call
yield()
to temporarily give it up. - Older systems: Windows 3.1, Mac OS ?
- One thread can hog the whole CPU.
- More efficient for some applications because fewer switches. Solaris "green threads".
Pre-emptive
- OS allocates time slice to a thread.
- At the end of the time slice, or when blocked, other higher or equal priority threads are given a time-slice.
- Used on most systems.
Operating system may choose
- Hard to write really portable multi-threaded applications.
Example - Long action
Problem
The user presses a button on the GUI interface that starts a long action. The single GUI thread is now in use, so the GUI interface becomes completely unresponsive until the action is completed.
Solution
For long actions, start a separate thread so that the GUI thread may continue to operate the interface.
Example - Slow IO
Problem
IO is relatively slow. Let's say you're writing a browser. It reads a web page that has a lot of links to images. If you get the images sequentially, the program will spend most of its time waiting for network IO operations to complete.
Solution
Start a separate thread for each image that must be loaded. The IO wait time is therefore reduced to the longest wait, not the sum of all waits.
Example - Animation
Problem
You want to show an animated image, but also continue regular processing. Every so many milliseconds you need to draw a new image. How can you do this while you are doing some other computation?
Solution
Start a separate thread for the animation that starts up at regular intervals. The javax.swing.Timer class is a class that helps you do this.
Thread Life Cycle States
- New - Created, but no one has requested it to start.
- Ready - It's in a queue ready to run and is waiting for the CPU.
- Running - It's currently running.
- Waiting - It's waiting for something. When finished waiting, goes to ready queue.
- Waiting. Someone needs to tell it to go (
notify()
/notifyAll()
) - Sleeping. Waiting for a time interval to expire.
- Blocked by IO. Completion of IO will put it in the ready queue again.
- Blocked by synchonization. Someone else has locked object that is needed.
- Waiting. Someone needs to tell it to go (
Thread Life Cycle Transition State Diagram
[ INSERT DIAGRAM HERE ]Thread Scheduling
- Every thread has a priority.
- The OS may not support this many levels.
- The OS scheduler chooses highest priority Ready thread to run.
- It's possible for low priority threads to "starve".
Thread class and Runnable Interface
- Runnable
- Must define the
run()
method. - Implement Runnable if you are only going to
start()
a tread.
- Must define the
- Thread class
- Implements Runnable, so must define run()
- Has other methods.
Synchronization
- Every object has a monitor.
- Only one thread can lock an object's monitor at one time.
- Calling a synchronized instance method locks that object's monitor.
- Other calls block when they call that synchronized method.
- When method returns, lock is freed.
- Scheduler may then run one of the blocked threads.
- Deadlocks are largely prevented, but will throw exception if detected.
- Blocks may also be synchronized.
Data Structures and Synchronization
- Before Java 1.2
- All data structures synchronized, eg, Vector
- There is overhead in entering synchronized methods.
- Java 1.2 Collections
- Newer data structures are NOT synchronized by default.
- Can create a synchronized wrapper if needed.
- Java 5
- Some concurrent data structures are added. These are carefully coded so they may be used by more than one thread without synchronization and without producing bad results.
- It can be difficult to verify that code can be executed concurrently.
- Remember that each thread has its own stack.
Daemon Threads
- Threads that are only uses for services should be marked as Daemon threads.
- Example: A timer thread.
th.setDaemon(true);
- If only daemon-threads remain, the program is terminated.
Thread Methods
Thread.currentThread()
- Returns current thread.Thread.sleep(millis)
- Sleeps current thread # milliseconds.th.start()
- Starts thread th.th.interrupt()
- Interrupts th.- If th is blocked, th throws InterruptedException.
- Otherwise a flag is set that must be tested by th.
th.isInterrupted()
- True if interrupted. Eg,if (Thread.currentThread().isInterrupted()) ...
th.join()
- Waits for th to "die".th.yield()
- Voluntarily allows other threads to execute.
Thread Example
- Create a thread. Do everything inside run() method.
Thread busyBee = new Thread() { public void run() { doAllThatWork(); } }
- Start the thread where appropriate. The start() method creates a new call stack
for this thread and then calls the run() method.
busyBee.start();
- If you call run() yourself, it will just run it in your thread.
Object Methods for Threads
obj.wait()
- Current thread waits until object unlocked bynotify()
call.obj.notify()
- Awakens arbitrary thread "waiting" for this object. Can only be called if current thread owns the lock on this object (eg, in a synchronized method). Arbitrary thread is still blocked until current thread releases lock.obj.notifyAll()
- Awakens all threads "waiting" for this object..
Timers
- javax.swing.Timer
- java.util.Timer
- [TODO: Insert example here]
GUI and Threads
- New GUI event-dispatching thread started by
setVisible()
. - Main thread can terminate after starting GUI.
- Listeners are called on the GUI thread.
- GUI is paralyzed if listeners take too long!
Separate Thread for Long Actions
- Start another "worker" thread for long processes.
- If response is still too slow, might have to lower priority of worker thread.
- Swing is not thread safe. After worker thread terminates, how is it going to update the GUI?
- Solution: Add a Runnable object to the GUI event queue (FIFO).
SwingUtilities.invokeLater(Runnable)
- The GUI thread will execute it when there is no conflict.
GUI Listener Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Thread m_busyBee = new WorkerBee(); Runnable m_showResults = new ResultsDisplayer(); JButton m_gatherBtn = new JButton("Gather Honey"); m_gatherBtn.addActionListener(new BeeListener()); . . . class ResultsDisplayer implements Runnable { public void run() { showWorkResults(); } } class WorkerBee extends Thread { public void run() { gatherHoney(); SwingUtilities.invokeLater(m_showResults); } } class BeeListener implements ActionListener { public void actionPerformed(ActionEvent e) { disableControlsEnableCancel(); m_busyBee.start(); } } |
Thread pools
- Assume you want to download hundreds of things.
- The simple solution is to start hundreds of threads.
- But this is inefficient. Run only perhaps 5 at one time.
- A "thread pool" can be used for this.
- See blogs.sun.com/roller/page/swinger?entry=swingworker_throttling_and_monitoring
Updates to make
- Analogy with database transactions.
- Give an example of simultaneous account updates, eg, as in Horstmann.
- What happens to other threads when System.exit() is called?
- Reference to Doug Lea's book.