9
MONITOR

DESCRIPTION

In general, an object may need to access shared resources such as files as part of its implementation to provide the services it is designed for. In a multithreaded environment, when methods of such an object are accessed simultaneously by more than one thread, it could result in unpredictable behavior. Instances of such incorrect and irregular behavior resulting from the concurrent access to an object’s methods by multiple threads are referred to as race conditions.

The monitor is a mechanism to obtain a lock on such an object to ensure that only one thread is allowed to execute any method on that object at any given time. Instead of keeping the responsibility on its client objects, the actual service provider object itself can be designed to be responsible to ensure that no two threads can execute its methods simultaneously. This can be accomplished using the monitor concept. In Java this can be accomplished by declaring the methods of an object using the synchronized keyword.

The following example demonstrates the use of synchronizing an object’s methods to prevent race conditions.


EXAMPLE

Let us build a utility class whose instances can be used to log messages in a multithreaded environment.

A simple message logging utility class can be designed as in Listing 9.1.

Other application objects can log messages to the log file by invoking the log method on a FileLogger instance. Inside the log method, the FileLogger performs the necessary file operations required to log an input message. It is to be noted that the log method is declared with the synchronized keyword. Without synchronization, when multiple threads simultaneously try to log messages by invoking the log method on the same FileLogger object, it could result in unpredictable behavior. This is because multiple threads try to perform the same set of open, write and close operations on the same log file at the same time.

The synchronized keyword ensures that only one thread is allowed to execute the log method on a given FileLogger object at any given point in time. This guarantee comes at a price. Declaring an object’s methods as synchronized can have negative impact on the performance of an application that makes use of those methods. In general, synchronized methods run many times slower than their nonsynchronized counterparts. Hence an object’s methods should be designed as synchronized methods only after careful consideration.


Listing 9.1 A Simple Message Logger

   public class FileLogger { 
    public synchronized void log(String msg) { 
      DataOutputStream dos = null; 
      try { 
       dos = new DataOutputStream( 
              new FileOutputStream("log.txt”,true)); 
       dos.writeBytes(msg); 
       dos.close(); 
    } catch (FileNotFoundException ex) { 
      // 
    } 
    catch (IOException ex) { 
      // 
    } 
  } 
}

An object can have any number of synchronized methods. For a thread to execute a synchronized method on an object, it needs to get a lock on that object. The thread holds the lock on the object as long as the method execution continues. While a thread holds a lock on an object, no other thread is given a lock on the same object and hence other threads cannot execute any of the synchronized methods on the same object.


PRACTICE QUESTIONS

1. Design a thread-safe LogReader class to read messages from the log file log.txt.

2. As can be seen from the example, the monitor concept ensures the prevention of race conditions by providing a lock on an object to a thread. Identify how to provide a lock on an entire class of objects when a thread is executing some code on an instance of that class. In other words, when a thread is executing a method on an object, no other thread should be allowed to execute the same method even on a different instance of the same class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.125.188