System Interface Guide

Java Threads on Solaris

The Java programming language requires that multithreaded programs be supported. All java interpreters provide a multithreaded programming environment. Many of these interpreters, however, support only a single processor form of multithreading. Thus, the threads of a Java program, in a conventional Java interpreter executing on a multiprocessor, do not execute fully concurrently; only one thread actually executes at a time.

The Solaris Java Virtual Machine interpreter takes full advantage of multiple-processor computing systems. It does this by using the intrinsic Solaris multithread facilities, which allow multiple threads of a single process to be scheduled onto multiple CPUs simultaneously. The result is a substantial increase in the degree of concurrency for a multithreaded Java program when it is run under Solaris JavaVM.

Figure 2-1 roughly illustrates how Java threads operate under Solaris JavaVM. A complete description of the operation of Solaris threads is in Multithreaded Programming Guide.

Figure 2-1 Java threads on Solaris

Graphic

Tuning Multithreaded Applications

To take full advantage of Solaris threads, a compute-bound application such as parallelized matrix multiplication, an application must use a native method to call thr_setconcurrency(3T). This insures that sufficient concurrency resources are available to the Java application to fully use multiple processors. This is not necessary for most Java applications and applets. The following code is an example of how to do this.

The first element is the Java application, MPtest.java, that will use MPtest_NativeTSetconc(). This application creates 10 threads, each of which displays an identifying line and then loops 10,000,000 times to simulate a compute bound activity.


Example 2-3 MPtest.java

import java.applet.*;
import java.io.PrintStream;
import java.io.*;
import java.net.*;

class MPtest {
		static native void NativeTSetconc();

		static public int        THREAD_COUNT = 10;

		public static void main (String args[]) {
			int i;
			// set concurrency on Solaris - sets it to sysconf(_SC_NPROCESSORS_ONLN);
			NativeTSetconc();
			// start threads
			client_thread clients[] = new client_thread[ THREAD_COUNT ];
			for ( i = 0; i < THREAD_COUNT; ++i ){
				clients[i] = new client_thread(i, System.out);
				clients[i].start();		
			}
		}

		static { System.loadLibrary("NativeThreads"); }
		}
}

class client_thread extends Thread {
		PrintStream out;
		public int        LOOP_COUNT   = 10000000;
		client_thread(int num, PrintStream out){
			super( "Client Thread" + Integer.toString( num ) );
			this.out = out;
			out.println("Thread " + num);
		}
		public void run () {
			for( int i = 0; i < this.LOOP_COUNT  ; ++i ) {
				;
			}
		}
}

The second element is the C stub file, MPtest.c, that is generated from MPtest.java by the utility javah(1). Do this by typing

% javah -stubs MPtest.java

The third element is the C header file, MPtest.h, that is also generated from MPtest.java by the utility javah(1). Do this by typing

% javah MPtest.java

The fourth element is the C function, NativeThreads.c, which performs the call to the C-library interface.


Example 2-4 NativeThreads.c

#include <thread.h>
#include <unistd.h>

void MPtest_NativeTSetconc(void *this) {
		thr_setconcurrency(sysconf(_SC_NPROCESSORS_ONLN));
}

Finally, combining the four files into the Java application, MPtest.class, is most easily done with a make file such as


Example 2-5 MPtest make file

# Make has to be done in two stages:
# first do "make MPtest"
# Then create NativeThreads.c to incorporate the native call
# to "thr_setconcurrency(sysconf(_SC_NPROCESSORS_ONLN))
# and then do "make lib".
# After this, you should be able to run "java MPtest" with
# LD_LIBRARY_PATH and CLASSPATH set to "."

JH_INC1=/usr/java/include
JH_INC2=/usr/java/include/solaris
CLASSPATH=.; export CLASSPATH

MPtest:
	javac MPtest.java
	(CLASSPATH=.; export CLASSPATH; javah MPtest)
	(CLASSPATH=.; export CLASSPATH; javah -stubs MPtest)
	cc -G -I${JH_INC1} -I${JH_INC2} MPtest.c NativeThreads.c \
		-o libNativeThreads.so
clean:
	rm -rf *.class MPtest.c MPtest.o libNativeThreads.so \
		NativeThreads.o *.h