Study guide: Achieve strong performance with threads, Part 4
Brush up on Java terms, learn tips and cautions, review homework assignments, and read Jeff’s answers to student questions
Glossary of terms
- fixed-delay execution
- A kind of timer task execution where the execution of each task subsequent to the first task occurs relative to the previous task execution’s actual execution time. Furthermore, if an execution delays because of garbage collection or some other background activity, all subsequent executions also delay.
- fixed-rate execution
- A kind of timer task execution where the execution of each task subsequent to the first task occurs relative to the first task execution’s actual execution time. Furthermore, if an execution delays because of garbage collection or some other background activity, two or more executions occur in rapid succession to maintain the execution frequency.
- inheritable thread-local variables
InheritableThreadLocal
objects that store values on a per-thread basis. Furthermore, a parent thread’s values are accessible to all child threads.- main memory
- Object heap memory.
- tasks
TimerTask
and subclass objects.- thread groups
java.lang.ThreadGroup
objects that group theThread
(andThread
subclass) objects of related threads.- thread-local variables
ThreadLocal
objects that store values on a per-thread basis.- timer
- An object that executes code either once or periodically, and either at some specified time or after a time interval.
- volatility
- Changeability.
- working memory
- Processor registers and cache.
Tips and cautions
These tips and cautions will help you write better programs and save you from agonizing over why the compiler produces error messages.
Tips
- Once you no longer need a hierarchy of
ThreadGroup
objects, callThreadGroup
‘svoid destroy()
method via a reference to theThreadGroup
object at the top of that hierarchy. If the topThreadGroup
object and all subgroup objects lack thread objects,destroy()
prepares those thread group objects for garbage collection. Otherwise,destroy()
throws anIllegalThreadStateException
object. However, until you nullify the reference to the topThreadGroup
object (assuming a field variable contains that reference), the garbage collector cannot collect that object. Referencing the top object, you can determine if a previous call was made to thedestroy()
method by callingThreadGroup
‘sboolean isDestroyed()
method. That method returns true if the thread group hierarchy was destroyed. - You can easily determine a thread group’s parent group by calling
ThreadGroup
‘sThreadGroup getParent()
method. For all thread groups, savesystem
, this method returns a nonnull reference. Forsystem
, this method returns null. You can also find out if a thread group is the parent, grandparent, and so forth of another thread group by callingThreadGroup
‘sboolean parentOf(ThreadGroup tg)
method. That method returns true if a thread, whose reference you use to callparentOf(ThreadGroup tg)
, is a parent (or other ancestor) of the group thattg
references—or is the same group as thetg
-referenced group. Otherwise, the method returns false. - To ensure that a read/write operation (outside a synchronized context) on either a long-integer shared field variable or a double-precision floating-point shared field variable succeeds, prefix the shared field variable’s declaration with keyword
volatile
. - Override
InheritableThreadLocal
‘schildValue(Object parentvalue)
method to make the child’s inheritable thread-local value a function of the parent’s inheritable thread-local value. - To terminate the currently running task without affecting other tasks, call
TimerTask
‘sboolean cancel()
method. That method cancels the current task so that it will never run again (assuming the task is repeating) after it finishes its current execution and returns a Boolean true value if either the task is a one-time task that has not yet run or a repeating task. False returns if a one-time task has already run, if it was never scheduled, or if it was cancelled.TimerTask
‘scancel()
method does not cancel any other tasks.
Cautions
- The
volatile
andfinal
keywords cannot appear together in a shared field variable declaration. Any attempt to include both keywords forces the compiler to report an error. - ThreadDeath is a powerful tool for causing a thread to terminate its execution. However, this tool is dangerous, and is the reason Sun deprecated the
stop()
method. When a thread throws aThreadDeath
object, all locked monitors unlock asThreadDeath
propagates up the method-call stack. Objects protected by these monitors become accessible to other threads. If those objects are in an inconsistent state, a program can experience erratic behavior, a database or file can corrupt, and so on. However, if you know that the thread is not holding any locks, you can safely throwThreadDeath
.
Homework
- If you do not specify a thread group for a newly created thread, to which thread group does the thread belong?
- Identify two uses for thread groups.
- Can you destroy the
system
thread group? - Does the
volatile
keyword provide an alternative to synchronization? - Why can you not declare a shared field variable to be
volatile
andfinal
? - Write a program that uses
InheritableThreadLocal
‘schildValue(Object parentvalue)
method to compute a child thread’s initial value, as a function of a parent thread’s initial value, for the inheritable thread-local variable. - Write a program that uses the
Timer
andTimerTask
classes to periodically run a pair of tasks. After one of those tasks runs five times, useTimerTask
‘scancel()
method to cancel that task. - In the article’s
Clock1
application, replaceTimer t = new Timer ();
withTimer t = new Timer (true);
. Recompile the source code and executejava Clock1
. What happens and why? - Why does the reference handler thread have a higher priority than the finalizer thread?
Answers to last month’s homework
Last month, I asked you complete the source code to the BB
(bounded buffer) application by supplying source code to the Buffer
class. I also told you to use the wait()
and notify()
methods. The source code to my version of the complete BB
application follows:
// BB.java
class BB
{
public static void main (String [] args)
{
Buffer buffer = new Buffer (5); // Buffer holds a maximum of 5 characters
new Writer (buffer).start ();
new Reader (buffer).start ();
}
}
class Buffer
{
private char [] buffer;
private int inspos = -1;
Buffer (int length)
{
buffer = new char [length];
}
public synchronized void put (char c)
{
if (isFull ())
try
{
wait ();
}
catch (InterruptedException e)
{
}
buffer [++inspos] = c;
notify ();
}
public synchronized char get ()
{
if (isEmpty ())
try
{
wait ();
}
catch (InterruptedException e)
{
}
char c = buffer [0];
System.arraycopy (buffer, 1, buffer, 0, inspos--);
notify ();
return c;
}
private boolean isEmpty ()
{
return (inspos == -1) ? true : false;
}
private boolean isFull ()
{
return (inspos == buffer.length - 1) ? true : false;
}
}
class Writer extends Thread
{
private Buffer buffer;
Writer (Buffer buffer)
{
this.buffer = buffer;
}
public void run ()
{
for (int i = 0; i < 26; i++)
buffer.put ((char) ('A' + i));
for (int i = 0; i < 26; i++)
buffer.put ((char) ('a' + i));
for (int i = 0; i < 10; i++)
buffer.put ((char) ('0' + i));
buffer.put ('*'); // Indicate end of data items
}
}
class Reader extends Thread
{
private Buffer buffer;
Reader (Buffer buffer)
{
this.buffer = buffer;
}
public void run ()
{
char c;
while ((c = buffer.get ()) != '*')
System.out.print (c);
System.out.print ('n');
}
}