Remote Places to go:
Contents:Under Windows '95 and NT, the operating system uses time-slicing to determine which thread should run.
If two threads have the highest priority of all the threads, and the priorities are the same, then a time-slicing system will alternate between the two threads, and a non-time-slicing system will pick one thread and run it until completion.
So, if you create two threads with the same priorities and run them, you may see different behaviour on different platforms.
Under Solaris, the situation is even more confusing, because JDK1.1.4
has an optional native threads pack that uses time-slicing. So, under
Solaris JDK1.1.4, if the native threads pack is installed, and the
THREADS_FLAG
is set to native
, then you get
time-slicing. If THREADS_FLAG
is set to green
, then you do not get time-slicing.
The Javasoft Java tutorial Thread Priority page has two Java files that can be run as an application:
RaceTest.java
SelfishRunner.java
java RaceTestUnder a time-sliced system, such as Windows NT, the calls to Thread #0 ad Thread1 will be intermingled, but not necessarily alternating:
bash$ java -classpath .\;/jdk1.1.3/lib/classes.zip RaceTest Thread #0, tick = 50000 Thread #1, tick = 50000 Thread #0, tick = 100000 Thread #0, tick = 150000 Thread #1, tick = 100000 Thread #0, tick = 200000 Thread #1, tick = 150000 Thread #1, tick = 200000 Thread #0, tick = 250000 Thread #1, tick = 250000 Thread #0, tick = 300000 Thread #1, tick = 300000 Thread #0, tick = 350000 Thread #1, tick = 350000 Thread #0, tick = 400000 Thread #1, tick = 400000Under a non-time sliced system such as Solaris with non-native threads, you will get something like:
cxh@brahe 83% setenv THREADS_FLAG green cxh@brahe 84% java RaceTest Thread #0, tick = 50000 Thread #0, tick = 100000 Thread #0, tick = 150000 Thread #0, tick = 200000 Thread #0, tick = 250000 Thread #0, tick = 300000 Thread #0, tick = 350000 Thread #0, tick = 400000 Thread #1, tick = 50000 Thread #1, tick = 100000 Thread #1, tick = 150000 Thread #1, tick = 200000 Thread #1, tick = 250000 Thread #1, tick = 300000 Thread #1, tick = 350000 Thread #1, tick = 400000 cxh@brahe 85%Under Solaris with JDK1.1.4 and native threads, we get time-slicing.
cxh@brahe 87% setenv THREADS_FLAG native cxh@brahe 88% java RaceTest Thread #0, tick = 50000 Thread #0, tick = 100000 Thread #1, tick = 50000 Thread #0, tick = 150000 Thread #1, tick = 100000 Thread #0, tick = 200000 Thread #1, tick = 150000 Thread #1, tick = 200000 Thread #0, tick = 250000 Thread #0, tick = 300000 Thread #1, tick = 250000 Thread #1, tick = 300000 Thread #0, tick = 350000 Thread #0, tick = 400000 Thread #1, tick = 350000 Thread #1, tick = 400000 cxh@brahe 9%If you run the applet version of RaceTest, then you will probably see output similar to the time-slicing output. I believe that this is because the applet has multiple threads running.
As you can see, whether time-slicing occurs depends on the operating system and the version of Java that is running. Well designed programs should not depend on time-slicing being present or absent.
Thread.yield()
The following classes demonstrate how to use Thread.yield()
to have the threads alternate:
PoliteRunner.java
RaceTest2.java
java RaceTest2Under Solaris, the output should be like:
cxh@brahe 103% java RaceTest2 Thread #0, tick = 50000 Thread #1, tick = 50000 Thread #0, tick = 100000 Thread #1, tick = 100000 Thread #0, tick = 150000 Thread #1, tick = 150000 Thread #0, tick = 200000 Thread #1, tick = 200000 Thread #0, tick = 250000 Thread #1, tick = 250000 Thread #0, tick = 300000 Thread #1, tick = 300000 Thread #0, tick = 350000 Thread #1, tick = 350000 Thread #0, tick = 400000 Thread #1, tick = 400000 cxh@brahe 104%If you run the applet version of RaceTest2, then the output should have the threads alternating.
If we have 4 threads that take 5 seconds each to produce results, then under time-slicing, all 4 threads should finish in 4*5 seconds, so the average time to get results is 20 seconds.
If we don't have time-slicing, then the first thread returns after 5 seconds, the second after 10 seconds, the third after 15 seconds and the fourth after 20 seconds. So the average time is 12.50 seconds.
The classic example of deadlock is the dining philosophers. The idea is that there are a bunch of philosophers sitting around a table. There is a bowl of rice in fron of each philosopher, and a single chopstick between each philosopher. A philosopher must have two chopsticks in order to eat. Once a philosopher has eaten, they put down both chopsticks so that another can eat.
The problem is that if each philosopher picks up the chopstick on the left, then no philosopher will be able to get to chopsticks, so they will literally starve because of deadlock :-)
The Ptolemy II Communicating Sequential Processes domain includes a Dining Philosophers Demo
The Javasoft tutorial includes a dining philosophers applet.
Java Threads, p 166-167 discusses some rules of thumb that help avoid deadlock:
Every thread has a priority. When there is competition for processing resources, threads with higher priority are generally executed in preference to threads with lower priority. Such preference is not, however, a guarantee that the highest priority thread will always be running, and thread priorities cannot be used to reliably implement mutual exclusion.So, be careful about using priorities.
Resourced
public void start() { if (_plotThread == null) { _plotThread = new Thread(this, "Plot"); _plotThread.start(); } }If the thread is
null
, then either the thread was never
started, or started and stopped. If the thread is null
,
we create a new thread and start it. If the thread is not
null
in an applet, then we have already started the
thread
public void stop () { _plotThread = null; }We set the thread to
null
here, but we could just call
_plotThread.stop()
. The
Javasoft Thread tutorial
says that stopping a thread is rather
drastic, if the thread is doing something critical, then the
applet might be left in an inconsistant state. Calling stop on a thread
can be somewhat like hitting Control-C
on a program -
the program might not cleanup properly before exiting.
Applets that use threads should implement the stop()
method so that when the user moves to another page the applet stops.
This is especially important for threads that produce sound or consume
cpu cycles. See the
Javasoft tutorial applet checklist
for more information.
public void run () { while (Thread.currentThread() == _plotThread) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e){ } }Here, we check to see if the
_plotThread
has been set to
null
by stop()
. If it is not null, then we
call repaint
, and sleep for one second.
When we sleep, other threads can run.
Apparently, in JDK1.0.2, which is what Netscape3.x was based on,
applets could see each other's threads and the threads in the system
thread group. In JDK1.1 this is not the case. Apparently, it was
possible to write an applet that would call stop()
on all the threads in other applets.
Here's a simple demo of the Thread Monitor Applet that will only work under Netscape 3.x or IE3.x
jdb
is the Java debugger that comes with Sun's JDK.
jdb
documentation (
Solaris and Linux,
Windows)
discusses how to run jdb
.
jdb
applet debugging tutorial for JDK 1.3
Unfortunately, in JDK1.1.4, appletviewer -debug
does not work:
cxh@carson 39% appletviewer -debug Blink.html I/O exception while reading: /export/carson/carson2/cxh/pt/tycho/java/devel/blink/-debug Make sure that -debug is a file and is readable.This is Sun Java bug #4087784
One workaround is to call jdb
like so:
cxh@carson 41% jdb sun.applet.AppletViewer Blink.html Initializing jdb... 0xee322068:class(sun.applet.AppletViewer) > run run sun.applet.AppletViewer Blink.html running ... main[1] sun.applet.AppletViewer exited cxh@carson 42%
jdb
and Emacsjdb
.
The jde
package is listed on the
Java IDE page (ftp site)
jde is installed on the local cluster, to run it, type:
M-x load-file /usr/tools/gnu/lib/emacs/ohm-lisp/jde-init.elTo run the debugger, you have to type
M-x jde-db
jde-init.el
supplies
a hacked up version of the jdb
defun so that
M-x jdb
sort of works.
jde bugs and nits:
X windows are not in use or not initializedThe fix is to edit
speedbar.el
and wrap the
(if (x-display-color-p
sexp at the end of the file with
(condition-case () (if (x-display-color-p) ... ) ;; monochrome (error nil))
sun.applet.Appletviewer
, then the
emacs process filter crashes.
http://java.sun.com/products/hotjava
.
With regard to threads, the key feature of HotJava1.1 is that you
can monitor threads by selecting the View
menu, then
Monitor
, then Threads
.
The HotJava help for threads says:
BTW - A common method of debugging applets is to useEach applet running in HotJava has its own thread group, whether or not it actually creates any threads. All the threads created by the applet belong to that applet's thread group.
In the Thread Monitor, a thread group (or applet group) is preceded either by
+
, which means the group is expanded to list all of the threads within it, or by>
, which means the thread group can be expanded. Double-click on the thread group to toggle between these two states.When you select an applet thread group or an individual thread within an applet thread group, the Kill button is activated to let you kill that thread or thread group. When you select an individual applet thread, you can also use the Raise priority and Lower prioritybuttons to raise and lower the thread priorities one level at a time.
System.out.println
to print debugging messages. The
HotJava FAQ
says that to view System.out.println
output, start
HotJava with
hotjava -log /dev/ttyYou can also set the
HOT_JAVALOG
environment variable.
See the FAQ for information about running HotJava under Windows.
t
while in the Java Console.
$PTII/util/testsuite/PrintThreads.java
# Print info about threads, see also $PTII/util/testsuite/PrintThreads.java proc jdkThreads {} { set currentThread [java::call Thread currentThread] set parent [$currentThread getThreadGroup] puts "ThreadGroup: [$parent toString]" # Figure out the root ThreadGroup while { ! [java::isnull $parent] } { set rootGroup $parent set parent2 [$parent getParent] set parent $parent2 } puts "Root ThreadGroup: [$rootGroup toString]" set threads [java::new {Thread[]} [$rootGroup activeCount]] $rootGroup enumerate $threads puts "Current Threads are:" for { set i 0} { $i < [$threads length]} {incr i} { set thread [$threads get $i] set currentThreadString "" if {$thread == $currentThread} { set currentThreadString " (Current Thread)" } puts "$i. [$thread toString] $currentThreadString" } puts "To get a stack trace for each thread:" puts " Under Unix, try 'kill -3 pid', where pid is the process id from ps" puts " Under Windows, try Control-Break" }
http://java.sun.com/j2se/1.4.1/changes.html
says:
A deadlock detection utility has been added to the Java HotSpot VM. The utility is invoked by a ctrl+\ (on Linux or the Solaris Operating Environment) or a ctrl-break (on Microsoft Windows) on the command line while an application is running. The utility detects Java-platform-level deadlocks, including locking done from the Java Native Interface (JNI), the Java Virtual Machine Profiler Interface (JVMPI), and Java Virtual Machine Debug Interface (JVMDI).When invoked, the utility displays a thread dump to standard out and indicates any Java-platform-level deadlocks it detects. Refer to this sample output. If the application is deadlocked because two or more threads are involved in a cylce to acquire monitors, then the list of such threads and monitors involved in the deadlocks are displayed. Note, however, that this will not find deadlocks involving threads waiting on monitors on which no signal will be forthcoming.
The following non-standard command-line flags are recognized by the VM.
-XX:+UseAltSigs - On the Solaris operating environment, the VM uses SIGUSR1 by default, which can sometimes conflict with applications that signal-chain SIGUSR1. -XX:+UseAltSigs will cause the VM to use signals other than SIGUSR1 and SIGUSR2 as the default. Available beginning in J2SE 1.4.1 on the Solaris Operating Environment. -XX:+UseConcMarkSweepGC - This flag turns on concurrent garbage collection. This collector executes mostly concurrently with the application. It trades the utilization of processing power that would otherwise be available to the application for shorter garbage collection pause times. -XX:+UseParallelGC - This flag enables garbage collection to occur on multiple threads for better performance on multiprocessor machines. Each of these new flags is non-standard, as indicated by the fact that they being with -XX, which means that they are subject to change without notice.