Programming in Java is supported in the Solaris JVM by any Solaris text editor, make(1S), and by the components shown in the following table.
Table 3-1 Java Programming Environment ComponentsComponent | Description |
---|---|
javac |
Java compiler. Translates Java source code files (name.java) into bytecode files (name.class) that can be processed by the interpreter (java(1)). Both Java applications and Java applets are compiled. |
javald |
Wrapper generator. Creates a wrapper that captures the environment needed to compile and run a Java application. Because the specified paths are not bound until the wrapper is invoked, the wrapper allows for relocation of the JAVA_HOME and CLASSPATH paths. |
java |
Java interpreter. Can be invoked as a command to execute a Java application or from a browser by HTML code to execute an applet. |
appletviewer |
Java applet viewer. This command displays specified document(s) or resource(s) and runs each applet referred to by the document(s). |
javap |
Java class file disassembler. Disassembles a javac compiled bytecode class file and prints the result to stdout. |
(For more information on using make(1S) see the chapter "make Utility" in the Programming Utilities Guide.)
The normal Java environment variables are shown in the following table.
Table 3-2 Java Environment VariablesVariable | Description |
---|---|
JAVA_HOME |
Path of the base directory of the Java software. For example, javac, java, appletviewer, javap, and javah are all contained in $JAVA_HOME/bin. Does not need to be set to use Solaris JVM. |
CLASSPATH |
A colon (:) separated list of paths to directories containing compiled *.class files for use with applications and applets. Used by javac, java, javap, and javah. If not set, all Solaris JVM executables default to /usr/java/lib/classes.zip. Does not need to be set to use Solaris JVM. |
PATH |
The normal executable search list can contain $JAVA_HOME/bin. |
The JVM tools are installed in /usr/java/bin and symbolic links to each executable are stored in /usr/bin. This means that nothing needs to be added to a user's PATH variable to use the newly installed JVM package. Also, all Solaris JVM executables default to the path /usr/java/lib/classes.zip to find the standard Java class library.
The base Java programming environment provides no debugger. A debugger is included in the optional unbundled Java WorkShopTM from Sun Microsystems.
Java programs are written in two forms: applications and applets.
Java applications are run by invoking the Java interpreter from the command line and specifying the file containing the compiled application.
Java applets are invoked from a browser. The HTML code interpreted by the browser names a file containing the compiled applet. This causes the browser to invoke the Java interpreter which loads and runs the applet.
Example 3-1 is the source of an application that displays "Hello World" on stdout. The method accepts arguments in the invocation, but does nothing with them.
// // HelloWorld Application // class HelloWorldApp{ public static void main (String args[]) { System.out.println ("Hello World"); } } |
Note that, as in C, the method or function to be initially executed is identified as main. The keyword public lets the method be run by anyone; static makes main refer to the class HelloWorldApp and no other instance of the class; void says that main returns nothing; and args[] declares an array of type String
To compile the application, enter
$ javac HelloWorldApp.java |
It is run by
$ java HelloWorldApp arg1 arg2 ... |
Example 3-2 is the source of the applet that is equivalent to the application in Example 3-1.
// // HelloWorld Applet // import java.awt.Graphics; import java.applet.Applet; public class HelloWorld extends Applet { public void paint (Graphics g) { g.drawstring ("Hello World", 25, 25); } } |
In an applet, all referenced classes must be explicitly imported. The keywords public and void mean the same as in the application; extend says that the class HelloWorld inherits from the class Applet.
To compile the applet, enter
$ javac HelloWorld.java |
The applet is invoked in a browser by HTML code. A minimum HTML page to run the applet is:
<title>Test</title> <hr> <applet code="HelloWorld.class" width=100 height=50> </applet> <hr> |
Correct execution of many Java applications depends on the values of the JAVA_HOME, CLASSPATH, and LD_LIBRARY_PATH environment variables. Because the values of these environment variables are controlled by each user, they can be set to arbitrary paths, with either path being unusual. Further, it is common for an application to require a unique value in the CLASSPATH variable.
javald(1) is a command that generates wrappers for Java applications. The wrapper can specify the correct paths for any or all of the JAVA_HOME, CLASSPATH, and LD_LIBRARY_PATH environment variables. It does so with no effect on the user's values of these environment variables. It also overrides the user's values for these environment variables during execution of the Java application. Further, the wrapper ensures that the specified paths are not bound until the Java application is actually executed, which maximizes relocatability of applications.
In general, avoid using a native method to access Solaris-specific functionality such as thr_setconcurrency(3THR), since the application is then tied to the Solaris environment and is no longer 100% Pure Java.
Most Java applications do not need to use thr_setconcurrency(3THR). The only cases in which it might be necessary would be, for instance, a demo with dummy threads that spin interminably or a compute-bound application such as matrix multiplication or a parallelized graphics computation.
A compute-bound application, such as parallelized matrix multiplication, must use a native method to call thr_setconcurrency(3THR). 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, then loops 10,000,000 times to simulate a compute-bound activity.
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, generated from MPtest.java by the utility javah(1). Enter
% javah -stubs MPtest.java |
The third element is the C header file, MPtest.h, also generated from MPtest.java by the utility javah(1). Enter
% javah MPtest.java |
The fourth element is the C function, NativeThreads.c, which performs the call to the C library interface.
#include <thread.h> #include <unistd.h> #include <jni.h> JNIEXPORT void JNICALL Java_MPtest_NativeTSetconc(JNIEnv *env, jclass obj) { thr_setconcurrency(sysconf(_SC_NPROCESSORS_ONLN)); } |
Finally, combining the four files into the Java application, MPtest.class, is most easily done with a make(1S) file such as shown in Example 3-4.
# Make has to be done in two stages: # first do "make MPtest" # Then create NativeThreads.c to incorporate the native call # to "thr_setconcurrency(_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 "." JAVA_HOME=/usr/java JH_INC1=${JAVA_HOME}/include JH_INC2=${JAVA_HOME}/include/solaris CLASSPATH=.; export CLASSPATH; MPtest: ${JAVA_HOME}/bin/javac MPtest.java (CLASSPATH=.; export CLASSPATH; ${JAVA_HOME}/bin/javah MPtest) (CLASSPATH=.; export CLASSPATH; ${JAVA_HOME}/bin/javah -jni MPtest)cc -G -I${JH_INC1} -I${JH_INC2} NativeThreads.c\ -lthread -o libNativeThreads.so clean: rm -rf *.class libNativeThreads.so NativeThreads.o *.h |
The mapping table shows the closest possible mapping of the Java threads API to the Solaris and POSIX APIs. This mapping is not exact and does not imply that you can convert a Solaris or POSIX threads program to a Java threads program (or vice versa) using the table. The table serves only to show a loose equivalence between the APIs and to some guidance to developers familiar with one API and interested in knowing its relationship to the corresponding API. A conceptual difference exists between using the Solaris APIs by way of procedural and layered programming in C, and using them by object-oriented programming techniques in Java.
The following examples show why the Java/Solaris API equivalence is loose.
The Java thread destroy method (Destroy()) is shown to correspond to POSIX pthread_cancel(). However, POSIX pthread_cancel() is incomplete without the concept of cancellation points and the use of pthread_cleanup_push() and pthread_cleanup_pop() to establish cleanup handlers around cancellation points. The Java threads API does not have a similar conceptual framework about destroying threads. In this sense, the two destroy techniques are very different.
As of JDK 1.1, the destroy() method has been deprecated.
The Java thread interrupt() method is shown as corresponding to POSIX pthread_kill(), but is quite different. Java has the concept of safe interruption points (for instance, wait()), whereas POSIX does not.
The Solaris readers/writer lock interfaces and the POSIX attributes do not have any close equivalent interfaces in Java.
Java Threads API |
Solaris Threads API |
POSIX Threads API |
---|---|---|
thr_create() | pthread_create() | |
activeCount() | ||
checkAccess() | ||
countStackFrames() | ||
currentThread() | thr_self() | pthread_self() |
destroy() | pthread_cancel() | |
dumpStack() | ||
enumerate() | ||
getName() | ||
getPriority() | thr_getprio() | pthread_ getschedparam() |
getThreadGroup() | ||
interrupt() | thr_kill() | pthread_kill() |
interrupted() | ||
isAlive() | ||
isDaemon() | ||
isInterrupted() | ||
join() | thr_join() | pthread_join() |
resume() | thr_continue() | |
run() | ||
setDaemon() |
THR_DAEMON flag | |
setName() | ||
setPriority() | thr_setprio() | pthread_ setschedparam() |
sleep() | sleep() | sleep() |
start() | ||
stop() | ||
suspend() | ||
Synchronization methods | ||
wait() | cond_wait() | pthread_cond_wait() |
notify() | cond_signal() | pthread_cond_signal() |
synchronized method synchronized statements |
mutexes |
pthread_mutexes |
The following methods operate on a thread group. The thread group feature is available in Java, but there is no corresponding feature in Solaris or POSIX:
activeCount()
activeGroupCount()
allowThreadSuspension()
checkAccess()
getMaxPriority()
getParent()
getName()
isDaemon()
list()
parentOf()
resume()
setDaemon()
stop()
suspend()
toString()
uncaughtException()
The following sections describe Java development tools.
JWS is a powerful, visual development tool for professional Java developers. It offers a complete, easy-to-use toolset for building Java applets and applications quickly and easily.
JWS uses its own Java interpreter and consists of eight applications, as shown in the following table.
Table 3-4 Java WorkShop Application ListApplication | Description |
---|---|
Portfolio Manager |
Creates and customizes portfolios of Java projects. It manages collections of objects and applets from which new applets and applications can be created. |
Project Manager |
Sets preferences and directories for a project. Organizes and saves locations and preferences so that developers need not memorize paths to components. |
Source Editor |
A point-and-click tool for creating and editing source code. Other components of Java WorkShop invoke the Source Editor at many points in the creation, compiling, and debugging processes. |
Build Manager |
Compiles Java source code to Java bytecode and locates errors in the source. In launching the Source Editor, the Build Manager links the developer to the Source Editor, allowing quick correction and compilation. |
Source Browser |
Displays a tree diagram that shows the class inheritance of all the objects in the project. It also lists all constructor and general methods in the project and allows string and symbol searches. The Source Browser links to the Source Editor to view the code. |
Debugger |
Provides an array of tools to control and manage the debugging process. By running the application or applet under a control panel, the developer can stop and resume threads, set break points, trap exceptions, view threads in alphabetical order, and see messages. |
Applet Tester |
Similarly to appletviewer, Applet Tester lets the developer run and test the applet. Use Build Manager to compile the applet, then run it with Applet Tester. |
Online Help |
Is organized into the topics "Getting Started," "Debugging Applets," "Building Applets," "Managing Applets," and "Browsing Source". There are also buttons for a table of contents and index. |
Visual Java |
An integrated Java GUI builder that has a point-and-click interface with a pallet of customizable pre-built GUI foundation widgets. |
For more JWS information, refer to http://www.sun.com/workshop/java/.