- Java Concurrency
- Threads
- Runnables
- Thread Termination
- Thread Control
- Thread Status
- Each Java thread is like a sequential Java program.
- A collection of Java threads is a concurrent Java program.
- There is no global state for a thread to access.
- A thread accesses (references to) class instances.
- Threads may share access to (references to) class instances.
- The JVM is a weak concurrent system.
- Weak systems make fewer promises, less useful promises.
- Weak systems are easy to build, but hard to use.
- Weak systems allow much variation among implementations.
- Also, the JVM is not a well-defined weak system.
- Like most things in Java, a thread is an instance of a class.
- The Thread class, which is rarely subclassed.
- A Thread instance represents a generic execution engine.
- By default, threads do no useful computations.
- Create a thread with
new
, like any Java class instance.
- A thread is dormant when created.
- Thread
t
begins executing when t.start()
is called.
-
public void start() throws IllegalThreadStateException
.
-
t.start()
eventually calls t.run()
.
- Thread
t
does specific work by calling t.run()
.
-
public void run()
.
- Whatever goes on inside
t.run()
is the real work of the thread.
- There are many other constructors, members and fields.
- Threads and runnables are complimentary.
- Threads have the ability but don't have the knowledge.
- Runnables have the knowledge but don't have the ability.
- The combination of Threads and Runnables leads to concurrent Java
programs.
- The Thread class implements the Runnable interface.
- Runnables are defined in
java.lang.Runnable
- The thread-default Runnable implementation does nothing.
See the complete code.
- Thread
t
terminates when t.run()
returns.
- Once it terminates, a thread can't be revived.
-
start()
will throw an Illegal Thread State Exception.
- The runnable (if explicit) is another matter.
- Threads are garbage collected, with all the problems that entails.
- Timeliness (finalization and all that).
- Forgotten and unneeded thread references.
- Inducing premature termination is a tricky and delicate matter.
- Exceptions are not the answer.
- Better left to the Runnable implementation.
-
t.stop()
asynchronously terminates thread t
.
- Dangerous - releases locks without clean-up.
- Depreciated as of Java 1.2.
-
t.destroy()
immediately terminates thread t
.
- Dangerous - no resource clean up; no locks are released.
- Never implemented.
- The
Thread Death
exception.
- An internal mechanism that escaped.
- Don't use any of these.
- Make termination a synchronization condition in your Runnable.
- Do not control threads directly; control the tasks they execute.
- Example - implementing mutual exclusion.
- Bad - Set maximum thread priority to get mutual exclusion.
- The JVM scheduler may ignore priority.
- Coarse grained.
- Difficult to enforce globally.
- Good - Implement a critical region using semaphores (or something).
- Done in the Runnable with complete control.
- Proper granularity.
- Enforcement meshed with access.
- Threads run asynchronously; their state is unknown.
- They may hold resources, be in a critical region.
- Disturbing a thread in a delicate state can lead to trouble.
-
t.suspend()
suspends thread t
's execution.
-
t
may be in a critical region or hold locks.
-
t.resume()
- continues t
's execution.
- Both are depreciated; don't use them.
-
t.yield()
- cede execution to some other thread.
- A hint only, the JVM may ignore it.
- Mostly useless; don't use it.
-
t.setPriority(p)
sets thread t
's priority to p
.
- Another hint; may be ignored.
-
t.setPriority(Thread.MAX_PRIORITY)
does not implement
atomicity.
- Mostly useless; don't use it.
-
t.sleep(n)
suspends thread t
's execution for at least n
milliseconds.
- The delay may be longer; milliseconds may differ.
- Thread status is tricky to deal with.
- Status notifications are asynchronous.
- Status is easily interfered with.
- Don't write code that depends on thread status.
- Concentrate instead on the task's status.
- Replace thread status with task synchronization.
- Example - waiting for n threads to terminate.
- Bad - waiting for each thread's termination status.
- Other threads may steal the status.
- Handling runaway threads difficult.
- Good - synchronizing on a shared counter.
- A specific class instance can't be intercepted.
- Alternate behaviors (e.g., timeouts) possible.
- Status is most useful when debugging.
-
Thread.currentThread()
returns the calling thread.
-
t.join()
blocks the calling thread until thread t
terminates.
- There's no value passed between joining and joined thread.
-
t.isAlive()
returns true iff thread t
is alive.
- Mostly useless because it suffers from interference.
-
t.getName()
returns thread t
's print name.
- Set by
t.setName(String)
or by a Thread constructor.
- Threads are virtual machines; Runnables are the programs they run.
- Understand and exploit the differences.
- Avoid subclassing Thread to eliminate Runnables.
- This confuses two concepts better kept separate.
- There's a small number of useful methods in Thread and Runnable.
-
start()
will get you far.
- Understand why you shouldn't use various unsafe methods.
- If you don't understand, you'll make the same mistakes.
- Don't control threads, control tasks via Runnables.
- Greater control, and less contact with the weak JVM.
This page last modified on 11 July 2002.