230 likes | 252 Views
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
E N D
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
Thread Priorities II package java.lang; public class Threadextends Object implements Runnable { // constants publicstaticfinalint MAX_PRIORITY = 10; publicstaticfinalint MIN_PRIORITY = 1; publicstaticfinalint NORM_PRIORITY = 5; // methods publicfinalintgetPriority(); publicfinal voidsetPriority(int newPriority); publicstaticvoidyield(); ... }
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
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
Delaying a Thread public class Threadextends Object implements Runnable { ... publicstaticvoidsleep(long ms) throws InterruptedException; publicstaticvoidsleep(long ms, int nanoseconds) throws InterruptedException; ... }
Thread executing Sleep Granularity Local drift Granularity difference between clock and sleep time Time specified by program Thread runnable here but not executing Interrupts disabled Time
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) }
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
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?
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
Timeout on Waiting II • There are two important points to note about this timeout facility • As withsleep, the timeout is a relative time and not an 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
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?
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
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 voidinterrupt(); // Interrupt all threads in the group. publicvoiduncaughtException(Thread t, Throwable e); // Called if a thread in the group // terminates due to an uncaught exception. }
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
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)
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
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
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
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
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
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
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