Sunday, May 12, 2013

Java Concurrency Part 3

This is the third part of the tutorial, and this link goes to the previous post java concurrency part 2


A common situation in programs with multiple threads is when two threads have access or share a single resource like a file, database connection, an object. This scenario can provoke error situations or data inconsistency.

To guarantee that only one thread will execute a critical section, prevent data inconsistency and errors, synchronizations mechanisms should be implemented.

 Java provides two basic mechanisms:
  • The keyword synchronized.
  • The java.util.concurrent.locks.Lock interface and its implementations.
Every object in java has a built in lock, that only comes into play when the object has synchronized some code.

If one thread has the lock of an object, no other thread can have the lock until the first thread releases it.
A thread can acquire more than one lock.

Example:

   
      public class Resource {  
           public synchronized void lock() {  
           System.out.println(“Begining, the thread ” + Thread.currentThread().getName() + “has the lock”);  
                try {                           
                     Thread.sleep(10000);  
                } catch (InterruptedException e) {  
                     e.printStackTrace();  
                }  
           System.out.println(“Ending, the thread ” + Thread.currentThread().getName() + “has the lock”);  
           }  
      }  
      public class Concurrent extends Thread {  
           Resource resource;  
           public Concurrent( Resource resource, String name) {  
                super(name);  
                this. resource = resource;  
           }  
           public void run(){  
                resource.lock();  
           }  
      }  
      .....  
      Resource resource = new Resource();  
      Concurrent c1 = new Concurrent(resource, “one”);  
       c1.start();  
      Concurrent c2 = new Concurrent(resource, “two”);  
      c2.start();  
      ......  

In the previous example two thread access concurrently a resource, but one thread has to wait to the other to finish using the resource since the resource is protected using the synchronized keyword, there is no guarantee which thread will acquire the resource first.

The messages in console should appear:

Begining, the thread one has the lock
Ending, the thread one has the lock
Begining, the thread two has the lock
Ending, the thread two has the lock

or

Begining, the thread two has the lock
Ending, the thread two has the lock
Begining, the thread one has the lock
Ending, the thread one has the lock

The messages for each thread appear consecutive and are not mix since each thread doesn't release the lock of the Resource object until it finishes executing the lock() method.

If the synchronized keyword is removed from the declaration of the lock() in the Resource class, the outcome of the program could be any, an example of the output would be:

Begining, the thread two has the lock
Begining, the thread one has the lock
Ending, the thread one has the lock
Ending, the thread two has the lock

The synchronized keyword can be applied to an object's instance to protect access of a block of code instead of a method, it has the same behavior, the thread who access the block of code tries to acquire the lock of the object.

Example:

 public class Resource {  
           public void lock() {  
                 synchronized(this) {  
           System.out.println(“Begining, the thread ” + Thread.currentThread().getName() + “has the lock”);  
                     try {                           
                          Thread.sleep(10000);  
                     } catch (InterruptedException e) {  
                          e.printStackTrace();  
                     }  
           System.out.println(“Ending, the thread ” + Thread.currentThread().getName() + “has the lock”);       
                }  
           }  
      }  
      ........  


The other synchronization mechanism provided by java is the Lock interface and its implementations, according to the java API “Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects”.

Lock interface provides several methods to obtain a lock from an object with different behaviors.

The following example is the same as the one used above with the synchronized keyword.

Example:

 public class Resource {  
           Lock lockObject = new ReentrantLock();  
           public void lock() {  
                lockObject.lock();//Adquires the lock  
           System.out.println(“Begining thread ” + Thread.currentThread().getName() + “has the lock”);  
                try {                           
                     Thread.sleep(10000);  
                } catch (InterruptedException e) {  
                     e.printStackTrace();  
                }  
           System.out.println(“Ending thread ” + Thread.currentThread().getName() + “has the lock”);  
                lockObject.unlock();//Releasing the lock  
           }  
      }  
      .......  


In the example the ReentrantLock implementation of the Lock interface was used, but the API provides more implementations with different behavior each.

ReentrantLock has another constructor which accepts a boolean parameter known as the fair parameter, and if it is false indicates that any thread that is waiting for the lock will receive it, but if it is true
indicates that the thread that has been waiting for the mos time for the lock will receive it.
                              Lock lock = new ReentrantLock(true);//fair set to true 

The lock() method tries to acquire the lock of the lock object, if another thread has the lock of the object, the thread waits until the thread that has the lock releases it.

When a thread finishes using a lock should invoke unlock() method to release the lock so other threads can access the lock.

The Lock interface has the tryLock() method, and it is similar to the lock() methd, but this method doesn't block waiting for a lock as lock() does, it returns a boolean value indicating if the lock was acquire or not, returns true if the lock was free and was acquired by the current thread, and false otherwise.
This method should be used inside an if() condition, if the lock is obtained a block of code is executed.

                                 If (lockObject.tryLock()) {
                                       .........
                                 }




No comments:

Post a Comment