[slides] Completing The Java Model
Download
Report
Transcript [slides] Completing The Java Model
Thread Priorities I
Although priorities can be given to Java threads, they
are only used as a guide to the underlying scheduler
when allocating resources
An application, once running, can explicitly give up the
processor resource by calling the yield method
yield places the thread to the back of the run queue
for its priority level
© Andy Wellings, 2004
Thread Priorities II
package java.lang;
public class Thread extends Object
implements Runnable {
// constants
public static final int MAX_PRIORITY = 10;
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
// methods
public final int getPriority();
public final void setPriority(int newPriority);
public static void yield();
...
}
© Andy Wellings, 2004
Warning
From a real-time perspective, Java’s scheduling and
priority models are weak; in particular:
no guarantee is given that the highest priority
runnable thread is always executing
equal priority threads may or may not be time
sliced
where native threads are used, different Java
priorities may be mapped to the same operating
system priority
© Andy Wellings, 2004
Delaying Threads: Clocks
Java supports the notion of a wall clock
java.lang.System.currentTimeMillis returns the
number of milliseconds since 1/1/1970 GMT and is used by
used by java.util.Date (see also
java.util.Calendar)
However, a thread can only be delayed from executing by
calling the sleep methods in the Thread class
sleep provides a relative delay (sleep from now for X
milliseconds, y nano seconds), rather than sleep until 15th
December 2003
© Andy Wellings, 2004
Delaying a Thread
public class Thread extends Object
implements Runnable
{
...
public static void sleep(long ms)
throws InterruptedException;
public static void sleep(long ms,
int nanoseconds)
throws InterruptedException;
...
}
© Andy Wellings, 2004
Sleep Granularity
Local drift
Time specified by
program
Granularity
difference
between
clock and
sleep time
Thread runnable
here but not
executing
Interrupts
disabled
Time
© Andy Wellings, 2004
Thread
executing
Drift
The time over-run associated with both relative and
absolute delays is called the local drift and it it cannot be
eliminated
It is possible, with absolute delays, to eliminate the
cumulative drift that could arise if local drifts were
allowed to superimpose
while(true) {
// do action every 1 second
sleep(1000)
}
© Andy Wellings, 2004
Absolute Delays I
Consider an embedded system where the software controller needs to
invoke two actions
The causes the environment to prepare for the second action
The second action must occur a specified period (say 10 seconds)
after the first action has been initiated
Simply sleeping for 10 seconds after a call to the first action will not
achieve the desired effect for two reasons
The first action may take some time to execute. If it took 1 second then a
sleep of 10 would be a total delay of 11 seconds
The thread could be pre-empted after the first action and not execute
again for several seconds
This makes it extremely difficult to determine how long the relative
delay should be
© Andy Wellings, 2004
Absolute Delays II
{
static long start;
static void action1() {...};
static void action2() {...};
try
{
start = System.currentTimeMillis();
action1();
Thread.sleep(
10000 - (System.currentTimeMillis() - start));
}
catch (InterruptedException ie) {...};
action2();
}
What is wrong with this approach?
© Andy Wellings, 2004
Timeout on Waiting I
In many situations, a thread can wait for an arbitrary long
period time within synchronized code for an associated
notify (or notifyAll) call
There are occasions when the absence of the call, within a
specified period of time, requires that the thread take
some alternative action
Java provides two methods for this situation both of which
allows the wait method call to timeout
In one case, the timeout is expressed in milliseconds; in
the other case, milliseconds and nanoseconds can be
specified
© Andy Wellings, 2004
Timeout on Waiting II
There are two important points to note about this timeout
facility
1. As with sleep, the timeout is a relative time and not an
2.
absolute time
It is not possible to know for certain if the thread has
been woken by the timeout expiring or by a notify
There is no return value from the wait method and no
timeout exception is thrown
© Andy Wellings, 2004
Timeouts on Waiting
public class TimeoutException extends Exception
{};
public class TimedWait
{
public static void wait(Object lock, long millis)
throws InterruptedException, TimeoutException
{
// assumes the lock is held by the caller
long start = System.currentTimeMillis();
lock.wait(millis);
if(System.currentTimeMillis() >= start + millis)
throw new TimeoutException();
}
}
What is wrong with this approach?
© Andy Wellings, 2004
Thread Groups I
Thread groups allow collections of threads to be grouped
together and manipulated as a group rather than as
individuals
They also provide a means of restricting who does what to
which thread
Every thread in Java is a member of a thread group
There is a default group associated with the main
program, and hence unless otherwise specified, all created
threads are placed in this group
© Andy Wellings, 2004
Thread Groups II
public class ThreadGroup
{
public ThreadGroup(String name);
// Creates a new thread group.
public ThreadGroup(ThreadGroup parent, String name);
// Creates a new group with the
// specified parent.
. . .
public final void interrupt();
// Interrupt all threads in the group.
public void uncaughtException(Thread t,
Throwable e);
// Called if a thread in the group
// terminates due to an uncaught exception.
}
© Andy Wellings, 2004
Thread Groups III
Hierarchies of thread groups to be created
Thread groups seem to have fallen from favour in recent
years
The deprecation of many of its methods means that there
is little use for it
However, the interrupt mechanisms is a useful way of
interacting with a group of threads
Also, the uncaughtException method is the only hook
that Java 1.4 provides for recovering when a thread
terminates unexpectedly
© Andy Wellings, 2004
Processes
Threads execute within the same virtual address space
and, therefore, have access to shared memory.
The Java languages acknowledges that the Java program
might not be the only activity on the hosting computer and
that it will executing under control of an operating system
Java, therefore, allows the programmer to create and
interact with other processes under that host system
Java defines two classes to aid this interaction:
java.lang.Process
java.lang.Runtime
(look them up on the web and in the book)
© Andy Wellings, 2004
Strengths of the Java Concurrency Model
The main strength is that it is simple and it is supported
directly by the language
This enables many of the errors that potentially occur with
attempting to use an operating system interface for
concurrency do not exists in Java
The language syntax and strong type checking gives some
protection
E.g., it is not possible to forget to end a synchronized block
Portability of programs is enhanced because the
concurrency model that the programmer uses is the same
irrespective of on which OS the program finally executes
© Andy Wellings, 2004
Weaknesses I
Lack of support for condition variable
Poor support for absolute time and time-outs on waiting
No preference given to threads continuing after a notify
over threads waiting to gain access to the monitor lock for
the first time
Poor support for priorities
Note Java 1.5 concurrency utilities
will provide some help here
© Andy Wellings, 2004
Weaknesses II
Synchronized code should be kept as short as possible
Nested monitor calls
should be avoided because the outer lock is not released when the
inner monitor waits (to release the lock causes other problems)
can lead to deadlock occurring
It is not always obvious when a nested monitor call is
being made:
methods in a class not labelled as synchronized can still contain a
synchronized statement;
methods in a class not labelled as synchronized can be overridden
with a synchronized method; method calls which start off as being
unsynchronized may be used with a synchronized subclass
methods called via interfaces cannot be labelled as synchronized
© Andy Wellings, 2004
Bloch’s Thread Safety Levels I
Immutable
Objects are constant and cannot be changed
Thread-safe
Objects are mutable but they can be used safely in a concurrent
environment as the methods are synchronized
Conditionally thread-safe
Objects either have methods which are thread-safe, or have
methods which are called in sequence with the lock held by the
caller
© Andy Wellings, 2004
Bloch’s Thread Safety Levels II
Thread compatible
Instances of the class provide no synchronization
However, instances of the class can be safely used in a concurrent
environment, if the caller provides the synchronization by
surrounding each method (or sequence of method calls) with the
appropriate lock
Thread-hostile
Instances of the class should not be used in a concurrent
environment even if the caller provides external synchronization
Typically a thread hostile class is accessing static data or the
external environment
© Andy Wellings, 2004
Summary I
Threads can have priorities but support is weak
Threads can delay themselves by using the sleep methods
which only supports relative time periods (intervals); it is
not possible to accurately sleep until an absolute time
Time-outs of waiting for events is supported via the wait
methods but it is not easy to determine whether the
timeout has expired or the event has occurred
Threads can be grouped together via the ThreadGroup
class
Hierarchies of groups can be formed and it is possible to interrupt
the whole group
© Andy Wellings, 2004
Summary II
Interaction with processes outside the virtual machine via
the Processes and RunTime classes
The Java model has both strengths and weaknesses
Bloch’s has defined thread safety levels
© Andy Wellings, 2004