Friday, 15 May 2015

Synchronization in Java

 Throughout the discussion of threads thus far, you've really only learned about threads from an asynchronous perspective. In other words, you've only been concerned with getting threads up and running and not worrying too much about how they actually execute. You can only think in these terms when you are dealing with a single thread or with threads that don't interact with the same data. In reality, there are many instances where it is useful to have multiple threads running and accessing the same data. In this type of scenario, the asynchronous programming approach just won't work; you must take extra steps to synchronize the threads so they don't step on each other's toes.

The problem of thread synchronization occurs when multiple threads attempt to access the same resources or data. As an example, imagine the situation where two threads are accessing the same data file; one thread may be writing to the file while the other thread is simultaneously reading from it. This type of situation can create some very unpredictable, and therefore undesirable, results.


Note
When data objects are shared between competing threads, they are referred to as condition variables.

When you are dealing with threads that are competing for limited resources, you simply must take control of the situation to ensure that each thread gets equal access to the resources in a predictable manner. A system where each thread is given a reasonable degree of access to resources is called a fair system. The two situations you must try to avoid when implementing a fair system are starvation and deadlock. Starvation occurs when a thread is completely cut off from the resources and can't make any progress; the thread is effectively frozen. Where starvation can apply to a number of threads individually, deadlock occurs when two or more threads are waiting for a mutual condition that can never be satisfied; they are starving each other.

A Hypothetical Example

A popular hypothetical example that more clearly demonstrates the problem of deadlock is the dining philosophers. The story goes that there are five hungry philosophers sitting around a table preparing to eat. In front of each philosopher is a bowl of rice, while between each philosopher there is a chopstick. To take a bite of rice, a philosopher needs two chopsticks: one from the left and one from the right. In this situation, the philosophers are equivalent to threads, with the chopsticks representing the limited, shared resources they all need access to. Their desired function is to eat the rice, which requires access to a pair of chopsticks.

The philosophers are only allowed to pick up one chopstick at a time, and they must always pick up the left chopstick and then the right. When a philosopher gets both chopsticks, he can take a bite of rice and then put down both chopsticks. This sounds like a pretty reasonable system of sharing the limited resources so everyone can eat. But consider what happens when each philosopher goes after the chopsticks with equal access to them. Each philosopher immediately grabs the chopstick to his left, resulting in every philosopher having a single chopstick. They all then reach for the chopstick on their right, which is now being held by the philosopher to their right. They are all waiting for another chopstick, so they each just sit holding a single chopstick indefinitely. Both figuratively and literally, they are starving each other!

This is a very good example of how a seemingly fair system can easily go awry. One potential solution to this problem is to force each philosopher to wait a varying amount of time before attempting to grab each chopstick. This approach definitely helps, and the philosophers will probably get to eat some rice, but the potential for deadlock, and therefore starvation, is still there. You are counting on blind luck to save the day and keep the philosophers well fed. In case you didn't guess, this isn't the ideal approach to solving deadlock problems.

You have two approaches to solving deadlock in a situation like this: prevention or detection. Prevention means designing the system so that deadlock is impossible. Detection, on the other hand, means allowing for deadlock but detecting it and dealing with its consequences when they arise. As with a medical illness, it doesn't take a huge mental leap to realize that prevention usually involves much less pain than detection, which results in sort of a chemotherapy for deadlock. My vote is clearly for avoiding deadlock in the first place. Besides, trying to detect deadlock can often be a daunting task in and of itself.

Getting back to the famished philosophers, the root of the problem is the fact that there is no order imposed on the selection of chopsticks. By assigning a priority order to the chopsticks, you can easily solve the deadlock problem; just assign increasing numbers to the chopsticks. Then force the philosophers to always pick up the chopstick with the lower number first. This results in the philosopher sitting between chopsticks 1 and 2 and the philosopher sitting between chopsticks 1 and 5 both going for chopstick 1. Whoever gets it first is then able to get the remaining chopstick, while the other philosopher is left waiting. When the lucky philosopher with two chopsticks finishes his bite and returns the chopsticks, the process repeats itself, allowing all the philosophers to eat. Deadlock has been successfully avoided!

Synchronizing Threads

If you're thinking the dining philosophers example seems fairly simple, you're right. But don't get too confident yet-real-world thread synchronization situations can get extremely messy. Fortunately, Java provides a very powerful solution to the whole issue: the synchronized modifier. The synchronized modifier is used to flag certain parts of your code as synchronized, resulting in limited, predictable access for threads. More specifically, only one thread is allowed access to a synchronized section of code at a time.
For synchronized methods, it works like this: each synchronized method is given a lock, which determines if it can be accessed, similar to a real lock. When a thread attempts to access the method, it must first see if it is locked, in which case the thread is denied access. If the method isn't locked, the thread gets access and the method then becomes locked. Pretty simple, right?

Note
Locks can apply to both methods as well as entire classes, but not directly to individual blocks of code. You are allowed to specify an object or class that is locked for a particular block of synchronized code, but the block itself isn't locked.
Synchronized sections of code are called critical sections, implying that access to them is critical to the successful threaded execution of the program. Critical sections are also sometimes referred to as atomic operations, meaning that they appear to other threads as if they occur at once. In other words, just as an atom is a discrete unit of matter, atomic operations effectively act like a discrete operation to other threads, even though they may really contain many operations inside.
You can use the synchronizedmodifier to mark critical sections in your code and make them threadsafe. Following are some examples of using the synchronizedmodifier:
synchronized public void addEmUp() { 
  float a, b;
  a += b;
  b += a;
}

public void moveEmOut() {
  Rectangle rect;
  synchronized (rect) {
    rect.width -= 2;
  }
  rect.height -= 2;
}
The first example shows how to secure an entire method and make it synchronized; only one thread is allowed to execute the addEmUpmethod at a time. The moveEmOutmethod, on the other hand, contains a synchronized block of code within it. The synchronized block protects the width of the rectangle from being modified by multiple threads at once. Notice that the rect object itself is used as the lock for the block of code. Also notice that the modification of the height of the rectangle isn't included in the synchronized block, and therefore is subject to access by multiple threads at once.

Note
It's important to note that even though there are legitimate situations where you will need to make a block of code synchronized, in general it is better to apply synchronization at the method level. Employing method synchronization as opposed to block synchronization facilitates a more object-oriented design and results in code that is easier to debug and maintain.
There is a subtle problem when using synchronized methods that you may not have thought about. Check out the following code sample:
public class countEngine {
  private static int count;
  public synchronized void decCount() {
    count--;
  }
}
The decCount method is synchronized, so it appears that the countmember variable is protected from misuse. However, countis a class variable, not an instance variable, because it is declared as being static. The lock on the synchronized method is performed on the instance object, so the class data isn't protected. The solution is to synchronize the block using the class as the locked object, like this:
public class countEngine {
  private static int count;
  public void decCount() {
    synchronized (getClass()) {
      count--;
    }
  }
}
Notice that the getClassmethod is called to retrieve the class for the synchronized block. This is a perfect example of where you have to use block synchronization over method synchronization to get a desired result.

Volatile Variables


In rare cases where you don't mind threads modifying a variable whenever they please, Java provides a means of maintaining the variable's integrity. The volatilemodifier allows you to specify that a variable will be modified asynchronously by threads. The purpose of the volatilemodifier is to protect against variable corruption through registered storage of the variable. In an asynchronous environment, corruption can sometimes occur when a variable is stored in CPU registers. The volatile modifier tells the runtime system to always reference a variable directly from memory, instead of using a register. Furthermore, the variable is read from and written back to memory after each access, just to be safe. It's fairly rare that you'll need to use the volatilemodifier, but if you feel like living on the edge, it's there for your enjoyment! 

Thread States in Java

 Thread behavior is completely dependent on the state a thread is in. The state of a thread defines its current mode of operation, such as whether it is running or not. Following is a list of the Java thread states:
  • New
  • Runnable
  • Not running
  • Dead

New

A thread is in the "new" state when it is first created until its start method is called. New threads are already initialized and ready to get to work, but they haven't been given the cue to take off and get busy.

Runnable

When the start method is called on a new thread, the runmethod is in turn called and the thread enters the "runnable" state. You may be thinking this state should just be called "running," because the execution of the runmethod means a thread is running. However, you have to take into consideration the whole priority issue of threads having to potentially share a single CPU. Even though every thread may be running from an end-user perspective, in actuality all but the one currently accessing the CPU are in a "runnable" wait state at any particular instant. You can still conceptually think of the "runnable" state as the "running" state; just remember that all threads have to share system resources.

Not Running

The "not running" state applies to all threads that are temporarily halted for some reason. When a thread is in this state, it is still available for use and is capable of re-entering the "runnable" state at some point. Threads can enter the "not running" state through a variety of means. Following is a list of the different possible events that can cause a thread to be temporarily halted:
  • The suspendmethod is called.
  • The sleepmethod is called.
  • The waitmethod is called.
  • The thread is blocking for I/O.
For each of these actions causing a thread to enter the "not running" state, there is an equivalent response to get the thread running again. Following is a list of the corresponding events that can put a thread back in the "runnable" state:
  • If a thread is suspended, the resumemethod is called.
  • If a thread is sleeping, the number of specified milliseconds elapse.
  • If a thread is waiting, the object owning the condition variable calls notifyor notifyAll.
  • If a thread is blocking for I/O, the I/O operation finishes.

Dead

A thread enters the "dead" state when it is no longer needed. Dead threads cannot be revived and executed again. A thread can enter the "dead" state through one of two approaches, which follow:
  • The runmethod finishes executing.
  • The stopmethod is called.
The first approach is the natural way for a thread to die; you can think of a thread dying when its runmethod finishes executing as death by natural causes. In contrast to this is a thread dying by way of the stopmethod; calling the stopmethod kills a thread in an asynchronous fashion.

Even though the latter approach sounds kind of abrupt, it is often very useful. For example, it's common for applets to kill their threads using stop when their own stop method is called. The reason for this is that an applet's stopmethod is usually called in response to a user leaving the Web page containing the applet. You don't want threads out there executing for an applet that isn't even active, so killing the threads makes perfect sense. 

Grouping Threads in Java

 Earlier you learned a little about the ThreadGroupclass, which is used to group threads together. Grouping threads is sometimes useful because it allows you to control multiple threads as a single entity. For example, the ThreadGroupclass has suspend and resumemethods, which can be used to suspend and resume the entire group of threads. What you haven't learned is how to actually manage thread groups, which is the focus of this section.
Every thread in the Java runtime system belongs to a thread group. You may be wondering how this is possible, considering the fact that you saw earlier how to create threads with no mention of a thread group. If you create a thread without specifying a thread group, the thread is added to the group that the current thread belongs to. The current thread is the thread where the new thread is created from. In some cases, there may not be a current thread, in which case the Java runtime system adds the thread to a default thread group called main.
You associate threads with a particular group upon thread creation. There is no way to alter the group membership of a thread once it has been created; in other words, you get one opportunity to specify the permanent group for a thread when you create the thread. The Thread class includes constructors for specifying the thread group for the thread:
Thread(ThreadGroup, String)
Thread(ThreadGroup, Runnable)
Thread(ThreadGroup, Runnable, String)
Each constructor takes a ThreadGroupobject as the first parameter. The first constructor also takes a string parameter, allowing you to give the thread a name. The last two constructors take a Runnableobject as the second parameter, which is typically an object of your own concoction that implements the Runnableinterface. Finally, the last constructor also takes a string parameter, allowing you to name the thread.
Before you can create any threads, you need to create a ThreadGroupobject. The ThreadGroup class defines two constructors, which follow:
ThreadGroup(String name)
ThreadGroup(ThreadGroup parent, String name)
The first constructor simply creates an empty thread group with the specified name. The second constructor does the same thing, but places the new thread group within the thread group specified in the parent parameter. This constructor allows you to nest thread groups.
Take a look at a quick example of creating a thread group and adding a few threads to it. The following code shows how to create and manage a thread group and a couple of member threads:
ThreadGroup group = new ThreadGroup("Queen bee");
Thread t1 = new Thread(group, "Worker bee 1");
Thread t2 = new Thread(group, "Worker bee 2");
t1.start();
t2.start();
...
group.suspend();
...
group.resume();
After the thread group is created, each thread is created and passed the ThreadGroup object. This makes them members of the thread group. Each thread is then started by calling the startmethod of each; the ThreadGroupclass doesn't provide a means to start all the thread members at once. Sometime later the thread group suspends both threads with a call to the suspendmethod. It then gets them running again by calling resume.
You can find out what group a thread belongs to by calling the getThreadGroup method. This method returns the ThreadGroupobject that the thread belongs to. You can then find out the name of the thread group by calling the getNamemethod defined in the ThreadGroupclass. The following code shows how to print the name of the thread group for a particular thread.

ThreadGroup group = t.getThreadGroup(); 
System.out.println(group.getName());

Scheduling and Thread Priority

 You may be wondering how any software system can be truly threaded when running on a machine with a single CPU. If there is only one physical CPU in a computer system, it's impossible for more than one machine code instruction to be executed at a time. This means that no matter how hard you try to rationalize the behavior of a multithreaded system, only one thread is really being executed at a particular time. The reality is that multithreading on a single CPU system, like the systems most of us use, is at best a good illusion. The good news is that the illusion works so well most of the time that we feel pretty comfortable in the thought that multiple threads are really running in parallel.


Note
Incidentally, this same rule applies to multiprocessing systems involving a single CPU. Even though it may look as though you're downloading a file and playing a game in parallel, under the hood the CPU is busy juggling the execution of each process.

How It Works

The illusion of parallel thread execution on a system with a single CPU is often managed by giving each thread an opportunity to execute a little bit of code at regular intervals. This approach is known as timeslicing, which refers to the way each thread gets a little of the CPU's time to execute code. When you speed up this whole scenario to millions of instructions per second, the whole effect of parallel execution comes across pretty well. The general task of managing and executing multiple threads in an environment such as this is known as scheduling. So far, I've described the most basic form of timesliced scheduling, where every thread is given equal access to the processor in small increments. In reality, this turns out not to be the best approach to managing thread execution.
Undoubtedly, there are going to be situations where you would like some threads to get more of the CPU's attention than others. To accommodate this reality, most threaded systems employ some type of prioritization to allow threads to execute at different priority levels. Java employs a type of scheduling known as fixed priority scheduling, which schedules thread execution based on the relative priorities between threads. It works like this: each thread is assigned a relative priority level, which determines the order in which it receives access to the CPU. High-priority threads are given first rights to the CPU, while low-priority threads are left to execute when the CPU is idle.
One interesting thing about Java's approach to scheduling is that it doesn't employ timeslicing. In other words, the currently executing thread gets to enjoy the complete control of the CPU until it yields control to other threads. Lower-priority threads must simply wait until high-priority threads give them a chance to execute. Threads with the same priority level are given access to the CPU one after the next. 


Note
The Java runtime system itself could be merely a single process within a timesliced multiprocessing system on a particular platform. In this way, the fixed priority scheduling employed in Java applies only to Java programs executing within the Java runtime environment.

A good example of a low-priority thread is the garbage collection thread in the Java runtime system. Even though garbage collection is a very important function, it is not something you want hogging the CPU. Because the garbage collection thread is a low-priority thread, it chugs along in the background freeing up memory as the processor allows it. This may result in memory being freed a little more slowly, but it allows more time-critical threads, such as the user input handling thread, full access to the CPU. You may be wondering what happens if the CPU stays busy and the garbage collector never gets to clean up memory. Does the runtime system run out of memory and crash? No-this brings up one of the neat aspects of threads and how they work. If a high-priority thread can't access a resource it needs, such as memory, it enters a wait state until memory becomes available. When all memory is gone, all the threads running will eventually go into a wait state, thereby freeing up the CPU to execute the garbage collection thread, which in turn frees up memory. And the circle of threaded life continues!

Establishing Thread Priority

When a new thread is created, it inherits its priority from the thread that created it. The Threadclass defines three constants representing the relative priority levels for threads, which follow:
MIN_PRIORITY
NORM_PRIORITY
MAX_PRIORITY
The Java garbage collection thread has a priority of MIN_PRIORITY, whereas the system thread that manages user input events has a priority of MAX_PRIORITY. Knowing this, it's a good idea to take the middle road for most of your own threads and declare them as NORM_PRIORITY. Generally speaking, this should happen without your having to do anything special because the parent thread you are creating threads from will likely be set to NORM_PRIORITY. If, however, you want to explicitly set a thread's priority, it's pretty easy-the Thread class provides a method called setPrioritythat allows you to directly set a thread's priority.
Incidentally, the thread priority constants are actually integers that define a range of priorities. MIN_PRIORITYand MAX_PRIORITY are the lower and upper limits of the range of acceptable priority values, while NORM_PRIORITY rests squarely in the middle of the range. This means that you can offset these values to get varying priority levels. If you pass a priority value outside the legal range (MIN_PRIORITYto MAX_PRIORITY), the thread will throw an exception of type IllegalArgumentException.
Getting back to the setPrioritymethod, you can use it to set a thread's priority like this:
t.setPriority(Thread.MAX_PRIORITY);
Likewise, you can use the getPrioritymethod to retrieve a thread's priority like this:
int priority = t.getPriority();
Knowing that thread priority is a relative integer value, you can fine-tune a thread's priority by incrementing or decrementing its priority value, like this:
t.setPriority(t.getPriority() + 1);

This statement moves the thread up a little in the priority list. Of course, the extents of the priority range determine the effectiveness of this statement; in the current release of Java, MIN_PRIORITYis set to 1 and MAX_PRIORITYis set to 10. 

Daemons in Java

 So far, you've been learning about threads that operate within the context of a parent program. Java provides support for another type of thread, called a daemon thread, that acts in many ways like an independent process. Unlike traditional threads, daemon threads belong to the runtime system itself, rather than a particular program. Daemon threads are typically used to manage some type of background service available to all programs. The garbage collection thread is a perfect example of a daemon thread; it chugs along without regard to any particular program performing a very useful service that benefits all programs.
You can set a thread as a daemon thread simply by calling the setDaemon method, which is defined in the Thread class, and passing true:
thread.setDaemon(true);
You can query a thread to see if it is a daemon thread simply by calling the isDaemon method, which is also defined in the Threadclass:
boolean b = thread.isDaemon();

The Java runtime interpreter typically stays around until all threads in the system have finished executing. However, it makes an exception when it comes to daemon threads. Because daemon threads are specifically designed to provide some type of service for full-blown programs, it makes no sense to continue to run them when there are no programs running. So, when all the remaining threads in the system are daemon threads, the interpreter exits. This is still the same familiar situation of the interpreter exiting when your program finishes executing; you just may not have realized there were daemon threads out there as well. 

Creating Threads in Java

 Threads aren't much use if you don't know how to create them. Fortunately, you have two options for creating and using threads in your own programs, which have already been alluded to when discussing the thread classes:
  • Derive your class from the Threadclass and override its runmethod.
  • Implement the Runnableinterface in your class and provide an implementation for the run method.
Both of these approaches revolve around providing a runmethod, which is where all the actual processing takes place. After a thread has been created and initialized, its runmethod is called and given the opportunity to perform whatever processing the thread is designed to provide. Because it provides all the processing power, the runmethod is the heart of a thread. It's not uncommon for the runmethod to consist of an infinite loop that performs some repetitive action like updating the frames of an animation. But enough about run for now; go ahead and create some threads!

Deriving from the ThreadClass

If your class isn't derived from a specific class, you can easily make it threaded by deriving it from the Threadclass. The following source code shows how to add thread functionality to a class by deriving from the Threadclass:
public class ThreadMe extends Thread {
  public run() {
    // do some busy work
  }
}
It's as easy as that! To use this class in a real program and set the thread in motion, you simply create a ThreadMeobject and call the startmethod inherited from Thread, like this:
ThreadMe me = new ThreadMe();
me.start();
The start method automatically calls run and gets the thread busy performing its processing. The thread will then run until the run method exits or the thread is stopped, suspended, or killed. If for some reason you want to stop the thread's execution, just call the stopmethod, like this:
me.stop();
If stopping the thread entirely is a little too abrupt, you can also temporarily pause it by calling the suspendmethod, like this:
me.suspend();
The suspend method puts the thread in a wait state, very similar to the state a thread enters when you call the wait method. When you decide the thread has waited long enough, just call resumeto get things rolling again, like this:
me.resume();

Implementing the RunnableInterface

If your class needs to derive from a class other than Thread, you are forced to implement the Runnableinterface to make it threaded. A very common situation where you have to do this is when an applet class needs to be threaded. Because applet classes must be derived from the Appletclass, and Java doesn't provide a mechanism for multiple inheritance, you have no other option but to implement the Runnableinterface to add threading support. You implement the Runnableinterface in a class like this:
public class ThreadYou implements Runnable {
   public run() {
     // do some busy work
   }
 }
As you can see, the only syntactic difference in this approach is that you use the implementskeyword instead of extends. However, notice that you can still use the extendskeyword to derive from another class, like this:
public class ThreadedApp extends Applet implements Runnable {
   public run() {
     // do some busy work
   }
 }
This is a very practical scenario involving an applet class with a run method that performs some type of threaded processing. Even though the definition of a class implementing the Runnableinterface is little different than directly deriving from Thread, there is a big difference when it comes to creating the thread and getting it running. Creating and running a threaded class implementing the Runnableinterface is a three-part process, as the following code shows:
ThreadYou you = new ThreadYou();
Thread t = new Thread(you);
t.start();
Unlike the previous approach involving creating a thread object and calling its start method, this approach requires you to create both an instance of your class and a separate instance of the Threadclass. You pass your object into the Threadclass's constructor, which gives it access to your runmethod. You then set the thread running by calling the thread object's start method. The thread in turn executes your object's runmethod. The thread knows your class has a runmethod because it implements the Runnableinterface.
If you have no need to access the thread after you get it started, the creation and starting of the thread can be combined into one statement, like this:
ThreadYou you = new ThreadYou();
new Thread(you).start();

This approach eliminates the creation of the local variable t, which makes the code a little more efficient. Of course, you may think the original code is easier to understand, in which case you should by all means stick with the clearer technique. 

The Thread Classes in Java

 The Java programming language provides support for threads through a single interface and a handful of classes. The Java interface and classes that include thread functionality follow:
  • Thread
  • Runnable
  • ThreadDeath
  • ThreadGroup
  • Object

Thread

The Thread class is the primary class responsible for providing thread functionality to other classes. To add thread functionality to a class, you simply derive the class from Thread and override the run method. The run method is where the processing for a thread takes place, and it is often referred to as the thread body. The Threadclass also defines startand stop methods that allow you to start and stop the execution of the thread, along with a host of other useful methods.

Runnable

Java does not directly support multiple inheritance, which involves deriving a class from
multiple parent classes. This brings up a pretty big question in regard to adding thread functionality to a class: how can you derive from the Thread class if you are already deriving from another class? The answer is: you can't! This is where the Runnableinterface comes into play.
The Runnable interface provides the overhead for adding thread functionality to a class simply by implementing the interface, rather than deriving from Thread. Classes that implement the Runnableinterface simply provide a runmethod that is executed by an associated thread object that is created separately. This is a very useful feature and is often the only outlet you have to incorporating multithreading into existing classes.

ThreadDeath

The ThreadDeath error class provides a mechanism for allowing you to clean up after a thread is asynchronously terminated. I'm calling the ThreadDeathan error class because it is derived from the Errorclass, which provides a means of handling and reporting errors. When the stop method is called on a thread, an instance of ThreadDeathis thrown by the dying thread as an error. You should only catch the ThreadDeath object if you need to perform cleanup specific to the asynchronous termination, which is a pretty rare situation. If you do catch the object, you must rethrow it so the thread will actually die.

ThreadGroup

The ThreadGroup class is used to manage a group of threads as a single unit. This provides you with a means to finely control thread execution for a series of threads. For example, the ThreadGroupclass provides stop, suspend, and resume methods for controlling the execution of all the threads in the group. Thread groups can also contain other thread groups, allowing for a nested hierarchy of threads. Individual threads have access to their immediate thread group, but not to the parent of the thread group.

Object

Although not strictly a thread support class, the Objectclass does provide a few methods that are crucial to the Java thread architecture. These methods are wait, notify, and notifyAll. The wait method causes a thread to wait in a sleep state until it is notified to continue. Likewise, the notify method informs a waiting thread to continue along with its processing. The notifyAll method is similar to notify except it applies to all waiting threads. These three methods can only be called from a synchronized method; don't worry, you'll learn more about synchronized methods a little later in this chapter.

Typically, these methods are used with multiple threads, where one method waits for another to finish some processing before it can continue. The first thread waits for the other thread to notify it so it can continue. Just in case you're in the dark here, the Object class rests at the top of the Java class hierarchy, meaning that it is the parent of all classes. In other words, every Java class inherits the functionality provided by Object, including the wait, notify, and notifyAll methods.

Thread Basics in Java

 The multithreading support in Java revolves around the concept of a thread. The question is, what is a thread? Put simply, a thread is a single stream of execution within a process. OK, maybe that wasn't so simple. It might be better to start off by exploring exactly what a process is.

A process is a program executing within its own address space. Java is a multiprocessing system, meaning that it supports many processes running concurrently in their own address spaces. You may be more familiar with the term multitasking, which describes a scenario very similar to multiprocessing. As an example, consider the variety of applications typically running at once in a graphical environment. As I write this, I am running Microsoft Word along with Internet Explorer, Windows Explorer, Inbox, CD Player, and Volume Control. These applications are all processes executing within the Windows 95 environment. In this way, you can think of processes as being analogous to applications, or stand-alone programs; each process in a system is given its own room to execute.

A thread is a sequence of code executing within the context of a process. As a matter of fact, threads cannot execute on their own; they require the overhead of a parent process to run. Within each of the processes I mentioned running on my machine, there are no doubt a variety of threads executing. For example, Word may have a thread in the background automatically checking the spelling of what I'm writing, while another thread may be automatically saving changes to the document I'm working on. Like Word, each application (process) can be running many threads that are performing any number of tasks. The significance here is that threads are always associated with a particular process.



Note
Threads are sometimes referred to as lightweight processes, implying that they are a limited form of a process. A thread is in fact very similar to a full-blown process, with the major difference being that a thread always runs within the context of another program. Unlike processes, which maintain their own address space and operating environment, threads rely on a parent program for execution resources.

I've described threads and processes using Windows 95 as an example, so you've probably guessed that Java isn't the first system to employ the use of threads. That's true, but Java is the first major programming language to incorporate threads at the heart of the language itself. Typically, threads are implemented at the system level, requiring a platform-specific programming interface separate from the core programming language. This is the case with C/C++ Windows programming, because you have to use the Win32 programming interface to develop multithreaded Windows applications.

Java is presented as both a language and a runtime system, so the Sun architects were able to integrate threads into both. The end result is that you are able to make use of Java threads in a standard, cross-platform fashion. Trust me, this is no small feat, especially considering the fact that some systems, like Windows 3.1, don't have any native support for threads! 

Multithreading and Native Methods in Java

 Even though the native methods are written in C, they still execute within the context of the Java environment, including multithreading. Native methods will sometimes have sections of code that modify global (class or application) data, which modify important state variables, or which must call non-re-entrant functions. (Some platform-specific APIs fall into this category.) These sections are called critical sections, because it is critical that no more than one thread executes the section of code at a time. Critical sections are not unique to native methods: the same issues exist when dealing with multithreading in pure Java code.
In order to ensure that the native methods maintain the application in a consistent state, these native methods will have to be synchronized with other threads. The simplest way to accomplish this is to declare the native methods as synchronized in the Java code. Sometimes, however, this will be insufficient, either for performance reasons (for example, a method that does a long computation, but only changes the condition variable infrequently), or because a multithreaded application needs to use an existing object that does not have synchronized methods (most do not).
In these cases, your native code can perform the synchronization directly. In Java code, you could put the critical section inside a synchronized block. The native method analogue to a synchronized block directly uses a monitor.
Monitors prevent two threads from simultaneously executing a section of code. Monitors were first introduced in C.A.R. Hoare's seminal paper "Communicating Sequential Processes" (Communications of the ACM, Vol. 21, No. 8, August 1978). Typically, each condition variable has a monitor associated with it. The monitor acts as a lock on that data. Unless a thread holds the monitor, it cannot modify or inspect that data. Obviously, a thread should hold the monitor as briefly as possible.

Note
In Java, critical sections are usually methods. You can synchronize blocks of code smaller than methods. However, this leads to complex code, with many failure modes. Deadlock prevention at the method level is fairly straightforward, but it becomes rapidly more difficult when dealing with many small blocks of synchronized code.
Even when dealing with native methods, it is best to use synchronization at the method level.
Monitors provide the Java runtime system support for thread synchronization. Every object instance has a unique monitor attached to it. In this case, the entire object is considered a condition variable. Through a trio of functions, native methods can also use monitors.
void MonitorWait(unsigned int, int); 
void MonitorNotify(unsigned int);
void MonitorNotifyAll(unsigned int);
These functions are analogous to the wait(), notify(), and notifyAll()functions in Java:

monitorWaitThis function blocks the executing thread until the monitor is notified. If you encounter a deadlock, the first place to start is to check each occurrence of monitorWait().
monitorNotifyThis function awakens no more than one waiting thread. It signals that the monitor is now available. It must only be called from the thread that holds the monitor. If an unhandled exception occurs while a thread holds the monitor, any threads waiting on the monitor will be blocked indefinitely.
monitorNotifyAllThis function awakens all threads waiting on the monitor. It signals that the monitor is now available.

Tip
Monitors are re-entrant, which means that a thread that already holds a monitor will not deadlock if it calls monitorWait again.
Monitor operations are atomic. They are not subject to race conditions (although the code that calls them is).
The Java implementation of monitors has a nice feature that helps to prevent deadlock. Consider this scenario: a synchronized native method calls monitorWait, to wait for another synchronized method (native or not) to notify the monitor. Because the first method is synchronized, it already holds the monitor when monitorWaitis called. How is the second method ever supposed to execute? The implementation of monitorWaitmakes this possible by releasing the monitor on entry. This allows the second method to execute and notify the monitor. Once the monitor is notified, the first thread awakens. On exit from monitorWait, the first thread acquires the monitor again.
All three of the monitor functions are declared as receiving an unsigned integer. To get the monitor for an object, use the obj_monitormacro on the object's handle.
Here is an example of a synchronized string. This is an example of a producer/consumer problem. (Most synchronization problems can be reduced to one of two classic examples, producer/consumer and the colorfully named "dining philosophers problem." In a producer/consumer problem, one thread produces data items while another consumes them. Both operations must be synchronized so that the consumer gets each item exactly once. Listing 19.9 contains the Java definition of the synchronized string class, SyncString. Listing 19.10 shows the native method implementations of the SyncString.Setand SyncString.Get methods. Note once again that this could easily have been accomplished without the use of native methods. You will find that native methods are only useful in a very small set of circumstances.

Listing 19.9. Java class for SyncString.
class SyncString {
    String str;
    int bAvail;

    public native synchronized void Set(String s);
    public native synchronized String Get(); 

    static {
       try {
           System.loadLibrary("SyncString"); 
       } catch (UnsatisfiedLinkError e) {
           System.err.println("Cannot find library SyncString.");
           System.exit(-1); 
       }
    }
}


Listing 19.10. Native language implementation for SyncString.
#include <StubPreamble.h>
#include "SyncString.h"


void SyncString_Set(struct HSyncString *this,
                    struct Hjava_lang_String *str)
{
    while(unhand(this)->bAvail == TRUE) 
        monitorNotify(obj_monitor(this)); 

    unhand(this)->bAvail = TRUE;
    unhand(this)->str = str;

    monitorNotify(obj_monitor(this));
}

struct Hjava_lang_String *SyncString_Get(struct HSyncString *this) 
{
    Hjava_lang_String *hstrTemp;

    while(unhand(this)->bAvail == FALSE) 
        monitorWait(obj_monitor(this)); 

    unhand(this)->bAvail = FALSE;
        hstrTemp = unhand(this)->str; 

    monitorNotify(obj_monitor(this));

    return hstrTemp;
}



Note
There are other functions that allow native code to construct new monitors not associated with an object. Use of these functions is strongly discouraged, due to the increasing difficulty of deadlock prevention in the face of many monitors.

Native Methods and Exceptions in Java

 Native methods can throw exceptions just like a regular Java method. As with any other method that throws an exception, the native method in the Java class must declare the exceptions that it can throw. This looks exactly like the throwsclause for any other method.
Your native code throws the actual exception using the SignalErrorfunction:
void SignalError(ExecEnv *ee, char *Exception, char *SourceHint);
The first argument is the exception environment to use for the exception. Generally, you will pass a NULLhere to indicate the current environment.
The second argument is the fully specified exception name. This name includes the package in which the exception is defined. It should also be specified as a path, replacing the usual period separators with forward slashes (that is, UNIX-style path separators).
The third argument is a source code hint. You can pass a string that describes the error or provides some useful details. This string will appear on the walkback if the exception is not handled. It is safe to pass a NULLhere. 

Using Java Strings from Native Methods in Java

 Because there is an "impedance mismatch" between Java strings and C strings, there are several convenience functions that allow C code to use the Java strings. Java strings offer several advantages over C strings, including reference counting, automatic memory management, and Unicode support. On the other hand, no C runtime library function or API function will expect a Java string. The utility functions provide a bridge between Java and C strings.
These functions are defined in javaString.h, which will be included automatically if you include StubPreamble.h:
  • The following function will print a Java string on stdout: 
    void javaStringPrint(Hjava_lang_String *)
  • The following function returns the length of the Java string, in characters:
    int javaStringLength(Hjava_lang_String *)
  • The following function will construct a new Java string from a given C string. The second argument indicates the length of the buffer passed in the first argument:
    Hjava_lang_String *makeJavaString(char *, int)
  • The following interesting function allocates some temporary memory for a C string initialized from the given Java string. Once all references to this storage are eliminated, the memory is automatically deallocated. In other words, as long as you keep this pointer in a variable, the memory is valid:
    char *makeCString(Hjava_lang_String *)
  • The following function uses "malloc" to allocate some memory for a C string initialized from the given Java string: 
    char *mallocCString(Hjava_lang_String *)
  • The following function will convert the characters of the given Java string into a unicode string. It assumes that the buffer passed in as the second argument already exists. The third argument specifies the buffer length. The function returns the unicode string's address:
    unicode *javaString2unicode(Hjava_lang_String *, unicode*, int)
  • The following function will convert the characters of the given Java string into a C string. It assumes that the buffer passed in as the second argument already exists. The third argument specifies the buffer length. The function returns the C string's address:
    char *javaString2Cstring(Hjava_lang_String *, char *, int)

Using Java Objects from Native Methods

 In native methods, all objects appear as handles. Handles are at the heart of the Java object model, but you will be shielded from directly manipulating handles. A group of C macros and functions permit you to deal with handles largely as an abstract type. So what can you do with a handle?

Accessing Instance Variables from Native Methods

For starters, you can access all of an object's instance variables-all those that are visible to your code, at least. In order for your native method to access the data members of your object, you dereference the handle with the macro unhand(). Unhand() is defined in the header file interpreter.h, which is included by StubPreamble.h. Listing 19.8 shows an example of accessing an object's instance variables from a native method.

Listing 19.8. Using unhand()to access instance variables.

typedef struct ClassUserInformation { 
   long iUserID;
} ClassUserInformation;
HandleTo(UserInformation);
...
void UserInformation_SetUserID(struct HUserInformation *hUI,
    long newValue)
{
   unhand(hUI)->iUserID = newValue;
}


What Are Handles, Anyway?
In the Java implementation, a handle is used to maintain references to objects. Handles allow the use of native languages to truly be "two-way." That is, the native methods can access instance variables and call other methods, just as pure Java methods can. Handles are at the very heart of the Java object model. In code, a handle is a small structure with two pointers, which together form an object instance. One points to the instance variables, the other to the method table (the vtable in C++ parlance). Handles for your classes are created automatically when you create the header file. (See the sidebar "Where Did HUserInformation Come From?")
By using pointers to handles to pass objects around, Java attains great efficiency. Because object manipulations work through handles, there is a single item of interest to the garbage collector, and a natural mechanism for marking objects in use or discarded.
The unhand() macro returns a pointer to an ordinary C structure. (For handles to objects of your class, it returns a pointer to the structure defined in your header file.) In all cases, the members of the C structure have the same names as the members of the Java class. The types may be different, however. Check Table 19.1 for the type mapping. You can read and write to the members of the structure. In fact, you can even pass pointers to them as arguments to other functions. They behave in all ways as members of ordinary C structures, because that is exactly what they are. When you use unhand()on a handle, you are actually looking at the fundamental Java implementation of an object. The structures you see using the handle are the real structures; there is no behind-the-scenes marshalling before the call.

Accessing Class Variables from Native Methods

Class variables (static variables) do not appear in the instance variable structure generated by javah. This is because they are not stored with each instance of a class, but rather with the class structure itself. The Java runtime provides a function that you can use to get a pointer to the class variable getclassvariable.
long *getclassvariable(struct ClassClass *cb, char *fname);
Notice that this function, like many other Java runtime functions, requires a pointer to the class structure. Fortunately, every object instance carries this pointer around. The obj_classblockmacro from interpreter.htakes an object handle as an argument and returns a pointer to the class structure.
Why does getclassvariablereturn a pointer to a long? It returns a pointer because the native language code should be able to modify the class variables, as well as see them. The return type is long, but in C, all pointers to data are the same size. So, it is safe to cast the returned pointer to a pointer to whatever type the class variable really is.
Be warned that unless your native methods are synchronized, modifying class variables can be problematic. Always remember that, even though this method is in C, it really is being called from a multithreaded environment. There may be other threads executing Java methods or native methods. They may be doing any number of things, including accessing the class variable at exactly the same time as the native method. Any time global data is involved, whether it is class-wide or truly global, synchronization is an issue. See "Multithreading and Native Methods" for more details.
Wouldn't it be nice if your native language code could also call Java code? Yes, it really would. Fortunately, we can do exactly that. It all starts with the object handle. (Where else?) You have to use a slightly more complicated mechanism than you might think at first. Calling another C function from a function pointer in a structure is something familiar to all of us, something like:
hUserInformation->Username();                 // DO NOT DO THIS!
Although this would have the net effect of transferring execution to the other function, it is not sufficient. Here's why: When calling a C function, a stack frame is created with the return address and some arguments. (Implementations vary somewhat; this is necessarily a very general description.) In Java, there is much more context provided for a function call. In addition to the processor stack, the JVM maintains a great deal of stack information on its own, internal stack. (Presumably, combining this stack with the processor stack, both in hardware, is one of the benefits of a "Java chip.")
In order to make the method call, we really have to ask the JVM to do the call for us. Here are the three functions declared in interpreter.h that will make these calls:
HObject *execute_java_constructor(ExecEnv *, char *classname,
   ClassClass *cb, char *signature, ...);
long execute_java_dynamic_method(ExecEnv *, HObject *obj,
   char *method_name, char *signature, ...);
long execute_java_static_method(ExecEnv *, ClassClass *cb,
   char *method_name, char *signature, ...);
Each function serves a specific purpose and is described separately in the following section.

Calling a Java Constructor

Native language code can construct an instance of any Java class that is currently loaded. Here again, the native code is hooking directly into the implementation of Java. Therefore, the new object will behave exactly as it would if you had constructed it in Java code. The general form of a native language constructor is this:
hNewObject = (HClassName *)execute_java_constructor(NULL, 
    "ClassName", NULL, "ConstructorSignature", ...);
The first parameter here is the ExecEnvor exception environment that applies to the constructor call. You can safely pass a NULLhere, and the constructor will operate with the default exception environment. If you are using sophisticated exception handling in your native code, please see the section "Native Methods and Exceptions."
The interesting pieces of this call are shown in italics. First of all, in order for the native method to use the object that gets constructed, it must know the object's class. Usually, this comes from including a header file for that class. Only a few classes have headers distributed with the JDK: ClassLoader, String, Thread, and ThreadGroup. However, by using javah, you can create header files for whatever classes you need. (See Chapter 14 for details.) If you do not need to access the object's methods or instance variables, you can cast the return value from execute_java_constructorto an HObject pointer. HObjectis the handle to the base class Object.

Loading Java Classes from Native Language Code
If you need to load a class directly from native code, you can call the function:
int LoadFile(char *filename, char *directory, char *SourceHint);
It is safe to pass NULL for SourceHint. This function will cause the ClassLoader to find the file and load it into memory. Once the class is loaded, its static block is executed. Be aware that the static block can throw an exception.
The ClassLoader also provides native code for the DoImport function.
int DoImport(char *name, char *SourceHint);
This will behave exactly as if the Java code had contained an "import name;" line.
The next item of interest in this call is the class name. This is a text string that specifies what class is to be instantiated. This class must already be loaded, or reside on the class path. When you pass a class name, the Java runtime must perform a lookup on the class itself. However, if you have a pointer to the class itself, you can leave the class name argument NULLand pass the ClassClass pointer in the third argument. For example, if you wanted to clone an existing object of any class, you might use code like this:
struct HObject *Cloner_Clone(struct HCloner *hCloner,
                             struct HObject *hObj)
{
   HObject *hNewInst;
   hNewInst = execute_java_constructor(NULL, NULL, 
                 obj_classblock(hObject), "(A)", hObj);
   return hNewInst;
}
This native method can clone any object that has a copy constructor. The macro obj_classblockis another of the handle convenience macros. For any object, it will return a pointer to the class structure for that object. Many of the built-in functions of the Java runtime require a pointer to the class structure "ClassClass".
The constructor signature is used to select which constructor to invoke. It is a character string that specifies the number and type of arguments to follow. Table 19.2 shows the possible characters and their meanings.
Table 19.2. Signature characters and their meanings.

Character
Meaning
A
Any (object)
[
Array (object)
B
Byte
C
Char
L
Class
;
End class
E
Enumeration
F
Float
D
Double
(
Function argument list start
)
Function argument list end
I
Int
J
Long
S
Short
V
Void
Z
Boolean
By concatenating characters from this set, you specify what arguments are to follow. Two characters have special significance: the parentheses indicate the beginning and end of the argument list. For a constructor, parentheses should enclose the entire argument list. For other methods, the signature will also indicate the return type of the method. In the preceding example, the signature is "(A)", which means the constructor must simply take one argument-an object instance. This implies that our constructor could receive objects of other classes as arguments. If we knew the class name, say Foo, for example, we could write the signature as "(LFoo;)", which means the constructor must take an instance of class Fooor its subclasses, as an argument. Here is a revised version of the Clone method, which takes into account the class name of the argument passed in:
struct HObject *Cloner_Clone(struct HCloner *hCloner,
                             struct HObject *hObj)
{
   HObject *hNewInst;
   char     signature[80]; 

   sprintf(signature, "(L%s;)", classname(obj_classblock(hObj))); 
   hNewInst = execute_java_constructor(NULL, NULL, 
                 obj_classblock(hObject), signature, hObj);
   return hNewInst;
}
Notice that, although "name" is a simple member of struct ClassClass, we use the classname macro (from oobj.h) instead of a direct access. In general, you should never access a structure member directly. Instead, use one of the macros provided in oobj.hor interpreter.h (both included by StubPreamble.h). The macros shield you from future changes to the structures. What if there is no macro to access a particular member? Then you probably are not meant to use that member in the first place!
After the constructor signature, you can place a variable length argument list. These are the arguments that will be passed to your constructor. You should be careful to make sure that the type, number, and order of your arguments match the signature. Otherwise, your constructor may be called with garbage for arguments.
If there is an error while calling the constructor, execute_java_constructorwill return NULL.

Calling a Java Method

Now for the really good part. You can call any Java method from native code. It all works through the handle to the object instance. If the method to be called is static, see the next section. For dynamic methods-including final and native methods-use the execute_java_dynamic_methodfunction:
long execute_java_dynamic_method(ExecEnv *, HObject *obj,
    char *method_name, char *signature, ...);
The first parameter is the same as the first argument to execute_java_constructor-an exception environment. Again, it is safe to pass a NULLfor this parameter. If you require more sophisticated exception handling for the native code, see "Native Methods and Exceptions."
The second parameter is the object instance itself. This can be any valid object handle, whether it was passed from Java code as an argument or constructed in the native method itself.
The next parameter is the name of the method to be invoked. If this method does not exist in the object passed, execute_java_dynamic_methodwill throw an exception.
Finally, the fourth argument is the signature of the instance method. Again, the signature indicates the type and number of arguments to be passed to the instance method being called. This must be the same number and type of remaining arguments in the call to execute_java_dynamic_method.
The signature for a method differs slightly from the signature for a constructor. A method signature needs to indicate the expected return type. The signature can show this with an extra character after the closing parenthesis. For example, consider a method that takes arguments of two classes and a float and returns a byte:
public byte[] FunkyMethod(Object fc, SecondClass sc,
                          float difference);
This method would have the signature "(ALSecondClass;F)B". The call to execute_java_dynamic_methodwould then have three arguments after the signature: a generic object, an instance of SecondClass, and a float.
The return value from execute_java_dynamic_methoddepends on the method being invoked. It is declared as long, however, so you will need to cast it to the appropriate type. (Because long is wide enough to hold any primitive type or a handle, it is safe to cast it to whatever the method really returns.) Be careful, though. Because you are calling the method by a function, not directly, the compiler cannot possibly notify you of any changes in the method definition.

Calling a Static Java Method

Calling a class method from native code is similar to calling a dynamic method. Use the execute_java_static_methodfunction:
long execute_java_static_method(ExecEnv *, ClassClass *cb,
   char *method_name, char *signature, ...);
This is entirely analogous to the execute_java_dynamic_methodfunction, with one crucial difference. Instead of taking an object instance as a parameter, execute_java_static_methodrequires a class structure. This class structure can come from an object instance, using the obj_classblockmacro, or it can be retrieved using the FindClassfunction:
ClassClass* FindClass(ExecEnv *ee, char *classname, bool_t resolve);
FindClass will return a pointer to the class structure for any class name you pass in. This function may cause several things to happen. First, the named class may be loaded, which will in turn cause the named class's static block to execute. Exceptions may be thrown by FindClassitself, if it cannot find the class, or by the static block of the named class, when it is loaded.

Like the other runtime functions that can throw exceptions, FindClasscan take an exception environment as an argument. As usual, it is safe to pass a NULL here, in which case FindClass will use the current exception environment.