The Solaris MT kernel is one of the most important components of the Solaris operating environment, enabling the Solaris system to be the only standard operating environment that provides this level of concurrency, sophistication, and efficiency.
Java on Solaris software leverages the multithreading capabilities of the kernel while also enabling you to create powerful Java applications using thousands of user-level threads for multiprocessor or uniprocessor systems, through a very simple programming interface.
The Java on Solaris environment supports the many-to-many threads model. As illustrated in Figure 2-4, the Solaris two-level architecture separates the programming interface from the implementation by providing an intermediate layer, called lightweight processes (LWPs). LWPs allow you to create fast and cheap threads through a portable application-level interface. To use LWPs, write applications using threads. The runtime environment, as implemented by a threads library, multiplexes and schedules runnable threads onto "execution resources," the LWPs.
Individual LWPs operate like virtual CPUs that execute code or system calls. LWPs are dispatched separately by the kernel, according to scheduling class and priority, so they can perform independent system calls, incur independent page faults, and run in parallel on multiple processors. The threads library implements a user-level scheduler that is separate from the system scheduler. User-level threads are supported in the kernel by the kernel-schedulable LWPs. Many user threads are multiplexed on a pool of kernel LWPs.
Solaris threads provide an application with the option to bind a user-level thread to an LWP, or to keep a user-level thread unbound. Binding a user-level thread to an LWP establishes an exclusive connection between the two. Thread binding is useful to applications that need to maintain strict control over their own concurrency, such as those that require real-time response. No Java API exists to perform the binding. Most Java applications do not require binding. If binding is required, a Solaris native method call can be made to perform the binding.
Therefore, all Java threads are unbound by default. Unbound user-level threads defer control of their concurrency to the threads library, which automatically expands and shrinks the pool of LWPs to meet the demands of the application's unbound threads.
The following unique features of Java on Solaris threads are available by default to all Java applications on Solaris:
Unbound Solaris threads: A Java thread is essentially the same as an unbound Solaris thread, with the inherent advantages of unbound threads.
The ability to share an LWP with several user-level threads
Automatic concurrency control for unbound threads. The threads library dynamically expands and shrinks the pool of LWPs to meet the demands of the application. See "Programming Compute-Bound, Parallellized Java Applications" for more information.
Extremely lightweight user threads that can be created, used, and discarded in very large numbers without consuming excessive system resources or degrading system performance
Synchronization primitives are not known to the kernel and do not consume any system resources.
MT features, unique to Solaris, are accessible by using native methods.
In general, accessing native Solaris features using native methods from a Java application is not recommended. Such usage could make the Java application non-portable, because it would not be 100% Pure JavaTM and would be tied to the Solaris platform only.
Though accessing Solaris-specific features from Java applications is not recommended, here is a list of those features to illustrate the richness of the Solaris MT architecture:
The ability to define bound or unbound threads for user or system level control of application concurrency. Note that a bound Java thread can be created only by way of native methods.
In addition, the application can control application concurrency through a programmatic interface. See "Programming Compute-Bound, Parallellized Java Applications" for more information.
The ability to bind a user-level thread (through native methods) to an LWP that is dedicated to a single processor. This feature is useful to real-time applications running on multiprocessor systems.
Synchronization primitives that have interprocess scopes
Synchronization primitives that can be placed in files and can have lifetimes beyond that of the creating thread.
Direct native support for Java's daemon threads. Daemon threads are threads that run in the background and have dedicated exit semantics enabling them to terminate independently of the processes that use them. Daemon threads are useful to libraries that need to create threads that are unknown to applications. The Solaris JVM does not utilize direct native support for Java's daemon threads, but might do so eventually.
The Solaris two-level model delivers unprecedented high levels of flexibility for meeting many different programming requirements. Certain programs, such as window programs, demand heavy logical parallelism. Other programs, such as matrix multiplication applications, must map their parallel computation onto the actual number of available processors. The two-level model allows the kernel to accommodate the concurrency demands of all program types without blocking or otherwise restricting thread access to system services.
The Java on Solaris design uses system resources efficiently as they are needed. Applications can have thousands of threads with minimal thread-use overhead. Threads execute independently, share process instructions, and share data transparently with the other threads in a process. Threads also share most of the operating system state of a process, can open files and permit other threads to read them, and allow different processes to synchronize with each other in varying degrees.
The Java on Solaris threaded model delivers the best combination of speed, concurrency, functionality, and kernel resource utilization.