Go Inside the Java Real-Time System

he Sun Java Real-Time System (Java RTS) is the first conformant commercial implementation of Java Specification Request (JSR) -001, the Real-Time Specification for Java (RTSJ). Although initially released in 2002, the RTSJ was updated in July 2006 to include some new features which are covered in this article.

Java RTS enables developers of real-time applications to take full advantage of Java while maintaining the predictability of current real-time development platforms, such as QNX, and other, custom, embedded systems. With Java RTS, real-time components and non-real-time components can coexist and share data on a single system. Java RTS features are delivered via a separate real-time enabled version of the Java VM. This VM can process both traditional Java SE components and Java RTS components, giving developers heretofore unforeseen flexibility. Sun offers an RTSJ-compliant Java VM that runs only on Solaris (both x86 and SPARC); whereas IBM offers one that runs on Linux with open-source real-time Linux extensions.

This article will demonstrate the advantages of Java RTS over the standard Java VM, as well as over C++, for applications that have soft and hard real-time requirements. To do this I’ve created a sample application that simulates a temperature control system that must react to real-world events (i.e. temperature change) to maintain an ideal operating temperature for a critical application, such as a nuclear power plant.

In this simulation, if the temperature control system is used in a nuclear power plant or for a ship’s engines, the result of an unforeseen delay in processing (i.e. from the garbage collector) can have dire consequences. Before I get into the specifics of the simulation application, I think it’s important to first discuss the concept of real time.

What is Real Time?
In computer science, real-time computing (RTC) is the study of hardware and software systems that are subject to a real-time constraint, such as operational deadlines for event-to-system response. Compare this to non-real-time software systems that do not have such deadlines, even if the goal is to perform quickly. Real time is often confused with “real fast.” In fact, quick performance is not necessarily a requirement in some real-time systems. For instance, a financial institution may need to perform settlement processing once a day at a certain time; hardly a high-performance requirement. Instead, real time is all about building systems that have deterministic behavior, with predictable, guaranteed, response times. Whether your software needs to check for an event once every millisecond, or once a day, it must do so predictably, without unforeseen delays, interruptions, or latency.

There are two basic types of real-time systems: hard and soft. A hard real-time system will experience a critical failure if time constraints are violated, whereas soft real-time systems tend to be flexible. A hard real-time system requires that its operations be performed correctly, and within their time constraints, to be considered successful. An operation performed after its deadline is strictly considered incorrect and of no value to the system. An example of a hard real-time system is an elevator, where the software must react to an event (such as a floor sensor) in order to behave properly (stop at the desired floor).

In soft real-time systems, some latency is acceptable, but overall system predictability is still mandatory. An example of a soft real-time system is a stock trading system used by professional traders. In this system, it may be a requirement for certain positions to be bought or sold when market events occur. A certain amount of system latency may be acceptable, but the event must still be reacted to within a deterministic period of time. To summarize, hard real-time systems require immediate system response, and soft real-time systems can withstand some bounded latency.

Real-Time Java
Often, real-time application developers will rely upon facilities within a real-time operating system, programming language, software framework, or a combination of all three, in order to achieve real-time behavior in their applications. Examples of such environments are QNX, VxWorks, Nucleus, and Solaris; each environment typically comes with tools and libraries for real-time application development.

Historically, Java has been discounted as a real-time language. This is due to the initial impression of Java being slow in its early years. Besides the fact that real-time behavior is not necessarily dependant on high performance, Java has come a long way in terms of raw performance. With just-in-time (JIT) compilation, coupled with the Sun HotSpot JVM, Java performance meets or exceeds that of similar applications written in C/C++.

Sun’s Java RTS is a separate implementation of Java that meets both soft and hard real-time requirements and requires a special JVM to run. However, Java RTS still maintains complete compatibility with existing Java SE 5 applications. In fact, it can run standard Java SE applications in the same JVM alongside applications developed to use its real-time facilities. Tests have shown that Sun’s Java RTS achieves maximum latencies of 15 microseconds, with around 5 microseconds of jitter. Yes, that’s microseconds, not milliseconds!

Currently, version 2 of Java RTS from Sun Microsystems only runs on Solaris 10, both x86 and SPARC versions. This is mainly because Solaris is a true real-time operating system. Java RTS hooks the OS to take advantage of its real-time support and to ensure that your real-time threads do not suffer from priority inversion. With priority inversion, an OS will temporarily boost the priority of lower priority threads to ensure they get CPU time. With Java RTS and Solaris, this won’t happen, further guaranteeing that your real-time threads will never get interrupted.

Java RTS can be viewed as Java SE with new features that provide real-time benefits. How deep you dive into these features is up to you and your application’s requirements. Here is a summary of the additional features of RTS:

  • Java SE 5 compatibility?Allows real-time and standard Java applications to run together.
  • RealtimeThread thread class?Used for soft real-time scheduling, this class uses a real-time garbage collector.
  • NoHeapRealtimeThread thread class?This class is used for hard real-time scheduling and synchronization (does not use the Java heap, and hence does not need the garbage collector).
  • Twenty-eight new levels of strictly enforced priority levels. The highest priority Java RTS thread is truly the highest priority thread in the system and will not be interrupted.
  • ScopedMemory memory model?This application-defined scope contains live objects, but these are destroyed immediately when the application exits the scope. Scopes allow your application to control precisely when objects are created and destroyed without garbage collection.
  • ImmortalMemory memory model?Objects created here are not destroyed until the application exits. You need to be careful what gets created here or you will run out of memory.
  • Asynchronous event handlers?These handle external events and allow you to schedule your application’s response without spoiling the temporal integrity of the overall system.
  • Asynchronous transfer of control?This allows you to transfer control from one thread to another or quickly terminate a thread, in a manner that is safe from a real-time perspective.
  • High-resolution timers?These timers have true nanosecond accuracy.
  • Safe direct physical memory access?This allows device driver code to be written in Java without resorting to native code

Java RTS Application Development
You can begin your journey into real-time development today with any Java application, assuming you have access to Java RTS (available from vendors that support the RTSJ specification, such as Sun or IBM). Simply change all instances of Thread in your code to RealtimeThread. Once you do this, you’re done. Your application will now achieve soft real-time behavior within those threads. To build a robust deterministic real-time system you will want to go further, however this is an excellent start that will prove ample for many real-time applications.

To use the RealtimeThread class in your system, you can either extend it directly, or implement Runnable and assign it to a real-time thread. The first example, shown in Listing 1, extends RealtimeThread and is straightforward. In this code, the main deviation from normal thread programming is the need to specify the thread’s priority via the PriorityParameters class, and the thread’s period (how often it wakes up to do work) via the PeriodicParameters class. These are passed into the RealtimeThread class constructor. Also note that instead of calling Thread.sleep in the thread’s run method, a call is made to RealtimeThread.waitForNextPeriod. This call uses a high-resolution timer and the internal real-time facilities of Java RTS, to ensure temporal behavior and sleep for the period specified in the thread’s constructor.

If you choose not to extend Thread or RealtimeThread, but prefer to implement Runnable instead, you can do that also. The code is similar; you instantiate the Runnable class as you normally would, and then create a RealtimeThread with the same parameters as before, plus the Runnable class object, as shown below.

// Instantiage the Runnable classMyRTClass2 runnableObj = new MyRTClass2();// Create the RealtimeThread thread and supporting parametersPriorityParameters sched =     new PriorityParameters(      PriorityScheduler.instance().getMaxPriority());PeriodicParameters period  =     new PeriodicParameters(new RelativeTime(1,0));RealtimeThread rtt =     new RealtimeThread( sched, period,                        null,null,null,                        runnableObj );

Your Runnable class will likely be devoid of any real-time specific code. However, it’s important to remember to call RealtimeThread.waitForNextPeriod instead of sleep, or you will not get real-time behavior. There are other facilities of Java RTS that you may choose to use, such as scoped memory, immortal memory, and NoHeapRealtimeThread. Let’s take a look at these now.

Scoped Memory; Immortal Memory; and NoHeapRealtimeThread
Scoped memory is represented by an object that you instantiate in your code and then use to create other objects within. The threads that execute within that scoped memory space govern the lifetime of those objects. When all threads exit the scoped memory space, all of the objects within it are de-allocated immediately.

Scoped memory areas can be nested, with a parent-child relationship, and behave like a stack. For instance, if a running real-time thread enters a scope, the scope it was in previously becomes the parent of the newly entered scope. When the thread leaves that scope, it will return to the original (parent) scope. There are some rules for scopes due to the need to maintain the proper parenting relationship. For instance, Java threads cannot be created within a scope; they must be created on the heap or in immortal memory, and can then enter a scoped memory area to execute. Let’s take a look at how this works.

In Listing 2, MyRTClass3 extends RealtimeThread and creates a scoped memory region of type LTMemory. This type of memory region is guaranteed to have constant, linear time for allocations that do not require the region to expand beyond its initial size. The class, Worker, is created on the heap and is provided to the scoped memory region via the method LTMemory.enter. The Worker object will then execute in its own thread within the scoped memory region. All objects created within that region will be freed when the thread exits.

Immortal memory is quite different from scoped or heap memory, as objects created within are not subject to garbage collection. Therefore, real-time applications should be judicious in their usage of this special memory region, as it represents a finite resource. Table 1 illustrates the complete set of memory access rules for all memory region types in Java RTS:

Table 1?The Java RTS Memory Access Rules

Stored in: Reference to heap Reference to immortal Reference to scoped
Heap Yes Yes No
Immortal Yes Yes No
Scoped Yes Yes Only the same or an outer scope
Local Variable Yes Yes Yes

The table shows that objects in the heap or in a scoped memory region can reference objects in immortal memory. However, scoped memory cannot be referenced by any memory region other than the scope itself or an outer scope (the parent scope, the parent’s parent, and so on).

There are different ways to use immortal memory:

  • You can directly create objects within it from any real-time thread:
    //  Create an immortal object directlytry{  Object inImmortal =       ImmortalMemory.instance().newInstance(Object.class);} catch (IllegalAccessException ae) {  ae.printStackTrace();} catch (InstantiationException ie) {  ie.printStackTrace();}
  • You can provide a Runnable class to enter the immortal memory region:
    import javax.realtime.*;public class MyRTClass4 extends RealtimeThread {  Object immortalObj;  public void run(){    //  Enter immortal memory and create an immortal object     ImmortalMemory.instance().enter(      new Runnable() {        public void run(){          MyRTClass4.this.immortalObj = new Object();        }     );  }  // ...}
  • You can explicitly create a RealtimeThread with the immortal memory region provided as a constructor parameter:
    // Instantiage the Runnable classMyRTClass runnableObj = new MyRTClass();// Create the RealtimeThread thread and supporting parametersPriorityParameters sched =     new PriorityParameters(      PriorityScheduler.instance().getMaxPriority());PeriodicParameters period  =     new PeriodicParameters(new RelativeTime(1,0));RealtimeThread rtt =     new RealtimeThread( sched, period, null,                        ImmortalMemory.instance(),                        null, runnableObj );

Regardless of how you choose to use it, immortal memory represents a paradigm shift in object allocation and usage in Java. This pattern may seem awkward at first, but it provides a safe memory region that is guaranteed to be free of garbage collection pauses for the life of your application. This is a crucial component of Java RTS that enables hard real-time behavior in applications that require it. Now let’s look again at the sample real-time application introduced earlier in the article.

The Sample Application
The sample temperature control application runs in both real-time and non-real-time mode to illustrate the benefits of Java RTS. The application contains a user interface in the form of a temperature gauge (see Figure 1). The green area represents a safe temperature, while the red areas represent the “danger zones.”


Figure 1. The sample application updates a visual temperature gauge to show the current temperature of the nuclear reactor core.
 
Figure 2. This figure shows the output of the sample application when run in real-time mode.

The application consists of the main thread, which drives the gauge display, and two additional worker threads. The first worker thread simulates the temperature sensor, which is set to increase or decrease the temperature by one degree every two milliseconds. The temperature will increase if the cooling system is off, or decreases if it’s on. The second worker thread is the temperature monitor thread, which will turn the cooling system on or off when the temperature gets close to the high or low thresholds, respectively.

In the real-time version of the system, the monitor thread is a RealtimeThread with a one-millisecond period. In the non-real-time version, this thread is a normal Java Thread that sleeps for one millisecond before checking the temperature. The code is otherwise the same in both instances; it simply looks for a command-line argument to indicate what type of thread to create.

To start the application in real-time mode, run the following command (see Figure 2 for the result):

> java –jar Temperature.jar  -realtime

To start the application in non-real-time mode, run the following command (see Figure 3 for the result):

> java –jar Temperature.jar 
Figure 3. This figure shows the output of the sample application when run in non-real-time mode (notice the warning messages in the console window).

Of course, you need a JSR-001 compliant Java RTS virtual machine to run it in real-time mode. If not, you’ll have to take my word for it: the results are dramatic. The real-time version maintains a safe temperature regardless of what else happens in the system. However, with the non-real-time version, the temperature constantly veers into the danger zones.

With Java RTS and Solaris, you can build Java applications today that meet soft and hard real-time requirements on reasonably well equipped x86/x64 and SPARC-based systems. Just remember that real-time is not about speed and performance, but is instead about predictability and determinism. It’s also not a simple matter of having a better garbage collector; Java RTS ensures that no system thread or process will interrupt your real-time Java threads, including processes external to the Java VM. Because of this, it’s important to choose a real-time Java VM that implements the RTSJ (JSR-001) specification, such as those offered by Sun, and IBM.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts