- 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.
- Calling
t.
start()
starts thread t
executing.
- Thread
t
does work by calling t.
run()
.
- Whatever goes on inside
t.run()
is the real work of the thread.
- There are many other thread 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.
- Thread
t
terminates when t.run()
returns.
- Once a thread terminates, it can't be restarted.
- 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
.
- The stopped thread has no opportunity to clean up.
- Locks held by the stopped thread are released.
- Depreciated as of Java 1.2.
-
t.
destroy()
immediately terminates thread
t
.
- The destroyed thread has no opportunity to clean up.
- Locks held by the destroyed thread are not released.
- Never implemented.
- The
ThreadDeath
exception.
- Don't use any of these.
- Make termination a synchronization condition in your Runnable.
- Do not control threads directly; control the Runnables they execute.
- Take mutual exclusion, for example.
- Mutual exclusion via maximum thread priority to get is a bad idea.
- The JVM scheduler may ignore priority.
- Coarse grained.
- Difficult to enforce globally.
- Mutual exclusion via semaphores (or something) is a good idea.
- 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()
cedes execution to some other thread.
- A hint only, the JVM may ignore it.
- Mostly useless; don't use it.
-
t.
setPriority(int)
sets thread t
's
priority to the given value.
- Another hint; the JFM may ignore it.
-
t.setPriority(Thread.MAX_PRIORITY)
does not implement
atomicity.
- Priority is mostly useless; don't use it.
-
t.
sleep(long)
suspends thread t
's
execution for at least the given number of milliseconds.
- The delay may be longer; milliseconds may differ.
- Thread status is tricky to deal with.
- Status is asynchronous, changing unpredictably.
- Thread
t
can easily interfere with its status.
- 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.
- Waiting for each thread's termination status is a bad idea.
- Synchronizing on a shared counter is a good idea.
- A specific class instance can't be intercepted.
- Providing alternate behaviors, such as timeouts, is possible.
- Status (thread name, in particular) is most useful when debugging.
-
currentThread()
returns a reference to 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.
- On the other hand, once terminated, a thread stays terminated.
-
t.
getName()
returns thread t
's print name.
- 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 1 July 2003.