Wednesday, 6 August 2014

Java - Thread Synchronization, Locking, Priority, Thread Scheduler, Wait And Notify, Joining, Deadlock

Thread Synchronization in JAVA
Threads share the same memory space, that is, they can share resources. However, 
there are critical situations where it is desirable that only one thread at a time has 
access to a shared resource. For example, crediting and debiting a shared bank 
account concurrently amongst several users without proper discipline, will 
jeopardize the integrity of the account data. Java provides high-level concepts for 
synchronization in order to control access to shared resources.

A lock is used to synchronize access to a shared resource. A lock can be associated 
with a shared resource. Threads gain access to a shared resource by first acquiring 
the lock associated with the resource. At any given time, at the most one thread can
hold the lock (i.e., own the monitor) and thereby have access to the shared resource.
A lock thus implements mutual exclusion.
In Java, all objects have a lock—including arrays. This means that the lock from any 
Java object can be used to implement mutual exclusion. By associating a shared 
resource with a Java object and its lock, the object can act as a guard, ensuring 
synchronized access to the resource. Only one thread at a time can access the 
shared resource guarded by the object lock.
The object lock mechanism enforces the following rules of synchronization:
A thread must acquire the object lock associated with a shared resource, before it 
can enter the shared resource. The runtime system ensures that no other thread 
can enter a shared resource if another thread already holds the object lock 
associated with the shared resource. If a thread cannot immediately acquire the 
object lock, it is blocked, that is, it must wait for the lock to become available.
When a thread exits a shared resource, the runtime system ensures that the object
lock is also relinquished. If another thread is waiting for this object lock, it can 
proceed to acquire the lock in order to gain access to the shared resource.
Classes also have a class-specific lock that is analogous to the object lock. 
Such a lock is actually a lock on the java.lang.Class object associated with
the class. Given a class A, the reference A.class denotes this unique Class 
object. The class lock can be used in much the same way as an object lock 
to implement mutual exclusion.The keyword synchronized and the lock form 
the basis for implementing synchronized execution of code. There are two 
ways in which execution of code can be synchronized:
  • synchronized methods
  • synchronized blocks

Synchronized Methods 
If the methods of an object should only be executed by one thread at a time, then 
the declaration of all such methods should be specified with the keyword synchronized.
A thread wishing to execute a synchronized method must first obtain the object's
lock,before it can enter the object to execute the method. This is simply achieved
by calling the method. If the lock is already held by another thread, the calling 
thread waits. No particular action on the part of the program is necessary. 
A thread relinquishes the lock simply by returning from the synchronized method, 
allowing the next thread waiting for this lock to proceed.
Synchronized methods are useful in situations where methods can manipulate the 
state of an object in ways that can corrupt the state if executed concurrently. A
stack implementation usually defines the two operations push and pop as 
synchronized, so that pushing and popping of elements are mutually exclusive
operations. If several threads were to share a stack, then one thread would, for 
example, not be able to push an element on the stack while another thread was 
popping the stack. The integrity of the stack is maintained in the face of several 
threads accessing the state of the same stack.
Synchronized Blocks
Whereas execution of synchronized methods of an object is synchronized on the 
lock of the object, the synchronized block allows execution of arbitrary code to 
be synchronized on the lock of an arbitrary object. The general form of the 
synchronized statement is as follows:

synchronized (<object reference expression>) { <code block> }

The <object reference expression> must evaluate to a non-null reference value, 
otherwise, a NullPointerException is thrown. The code block is usually related to 
the object on which the synchronization is being done. This is the case with 
synchronized methods, where the execution of the method is synchronized on the 
lock of the current object:
    
public Object pop() { 
  synchronized (this) {
     // Synchronized block on current object // ... 
     } 
}

Once a thread has entered the code block after acquiring the lock on the specified
object, no other thread will be able to execute the code block, or any other code 
aquiring the same object lock, until the lock is relinquished. This happens when 
the execution of the code block completes normally or an uncaught exception is 
thrown. In contrast to synchronized methods, this mechanism allows fine-grained 
synchronization of code on arbitrary objects.
Object specification in the synchronized statement is mandatory. A class can 



choose to synchronize the execution of a part of a method, by using the this 
reference and putting the relevant part of the method in the synchronized block. 
The braces of the block cannot be left out, even if the code block has just one statement.

           class SmartClient {
                     BankAccount account;
                     public void updateTransaction() {
                     synchronized (account) {
                     synchronized block account.update(); 
         }

    }
}

Synchronized blocks can also be specified on a class lock:

     synchronized (<class name>.class) { <code block> }

The block synchronizes on the lock of the object denoted by the reference 
<class name>.class. A static synchronized method classAction() in class A 
is equivalent to the following declaration:

      static void classAction() {
                 synchronized (A.class) {  }
      }
In summary, a thread can hold a lock on an object
  • by executing a synchronized instance method of the object
  • by executing the body of a synchronized block that synchronizes on the object
  • by executing a synchronized static method of a class
Thread Priorities
Every Java thread has a priority that helps the operating system determine the 
order in which threads are scheduled.Java thread priorities are in the range 
between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). 
By default, every thread is given priority NORM_PRIORITY (a constant of 5).
Threads with higher priority are more important to a program and should be 
allocated processor time before lower-priority threads. However, thread priorities
cannot guarantee the order in which threads execute and very much platform 
dependentant.

Thread Scheduler
Schedulers in JVM implementations usually employ one of the two following strategies:
Preemptive scheduling.If a thread with a higher priority than the current running
thread moves to the Ready-to-run state, then the current running thread can be 
preempted (moved to the Ready-to-run state) to let the higher priority thread execute.
Time-Sliced or Round-Robin scheduling.
A running thread is allowed to execute for a fixed length of time, after which it 
moves to the Ready-to-run state to await its turn to run again.
It should be pointed out that thread schedulers are implementation- and
platform-dependent; therefore, how threads will be scheduled is unpredictable, at 
least from platform to platform.

Waiting and Notifying
Waiting and notifying provide means of communication between threads that 
synchronize on the same object. 
The threads execute wait() and notify() (or notifyAll()) methods on the shared object 
for this purpose. These final methods are defined in the Object class, and therefore, 
inherited by all objects.These methods can only be executed on an object whose 
lock the thread holds, otherwise, the call will result in an IllegalMonitorStateException.

final void wait(long timeout) throws InterruptedException final void wait(long 
timeout, int nanos) throws InterruptedException 
final void wait() throws InterruptedException. A thread invokes the wait() method 
on the object whose lock it holds. The thread is added to the wait set of the object.

final void notify() final void notifyAll() A thread invokes a notification method on 
the object whose lock it holds to notify thread(s) that are in the wait set of the 
object. Communication between threads is facilitated by waiting and notifying,
A thread usually calls the wait() method on the object whose lock it holds because
a condition for its continued execution was not met. The thread leaves the Running 
state and transits to the Waiting-for-notification state. There it waits for this condition 
to occur. The thread relinquishes ownership of the object lock.
Transition to the Waiting-for-notification state and relinquishing the object lock 
are completed as one atomic (non-interruptable) operation. The releasing of the 
lock of the shared object by the thread allows other threads to run and execute 
synchronized code on the same object after acquiring its lock.
Note that the waiting thread does not relinquish any other object locks that it 
might hold, only that of the object on which the wait() method was invoked. 
Objects that have these other locks remain locked while the thread is waiting.
Each object has a wait set containing threads waiting for notification. Threads 
in the Waiting-for-notification state are grouped according to the object 
whose wait() method they invoked.A thread in the Waiting-for-notification state 
can be awakened by the occurrence of any one of these three incidents:

  • The waiting thread times out.
  • Another thread interrupts the waiting thread.
  • Another thread invokes the notify() method on the object of the waiting and the waiting thread is selected as the thread to be awakened.
Notify

Invoking the notify() method on an object wakes up a single thread that is waiting
on the lock of this object. The selection of a thread to awaken is dependent on the
thread policies implemented by the JVM. On being notified, a waiting thread first 
transits to the Blocked-for-lock-acquisition state to acquire the lock on the object, 
and not directly to the Ready-to-run state. The thread is also removed from the 
wait set of the object. Note that the object lock is not relinquished when the 
notifying thread invokes the notify() method. The notifying thread relinquishes the 
lock at its own discretion, and the awakened thread will not be able to run until 
the notifying thread relinquishes the object lock.
When the notified thread obtains the object lock, it is enabled for execution,
waiting in the Ready-to-run state for its turn to execute again. Finally, when it does
get to execute, the call to the wait() method returns and the thread can continue
with its execution.

A call to the notify() method has no consequences if there are no threads in the
wait set of the object.

In contrast to the notify() method, the notifyAll() method wakes up all threads in
the wait set of the shared object. They will all transit to the
Blocked-for-lock-acquisition state and contend for the object lock as explained
earlier.

Joining

A thread can invoke the overloaded method join() on another thread in order to
wait for the other thread to complete its execution before continuing, that is, the
first thread waits for the second thread to join it after completion. A running
thread t1 invokes the method join() on a thread t2. The join() call has no effect if
thread t2 has already completed. If thread t2 is still alive, then thread t1 transits
to the Blocked-for-join-completion state. Thread t1 waits in this state until one of
these events occur-
Thread t2 completes-In this case thread t1 is enabled and when it gets to run, it
will continue normally after the join() method call.
Thread t1 is timed out.-The time specified in the argument in the join() method
call has elapsed, without thread t2 completing. In this case as well, thread t1 is
enabled. When it gets to run, it will continue normally after the join() method call.
Thread t1 is interrupted-Some thread interrupted thread t1 while thread t1 was
waiting for join completion. Thread t1 is enabled, but when it gets to execute, it
will now throw an InterruptedException.

Deadlocks

A deadlock is a situation where a thread is waiting for an object lock that another
thread holds, and this second thread is waiting for an object lock that the first
thread holds. Since each thread is waiting for the other thread to relinquish a
lock, they both remain waiting forever in the Blocked-for-lock-acquisition state.
The threads are said to be deadlocked.

Thread t1 has a lock on object o1, but cannot acquire the lock on object o2.
Thread t2 has a lock on object o2, but cannot acquire the lock on object o1.
They can only proceed if one of them relinquishes a lock the other one wants,
which is never going to happen.

     public class DeadlockExample { 

           public static void main(String[] args) {
             final String resource1 = "ratan jaiswal";
             final String resource2 = "vimal jaiswal";
             // t1 tries to lock resource1 then resource2
             Thread t1 = new Thread() {
                 public void run() {
                   synchronized (resource1) {
                       
                        System.out.println("Thread 1: locked resource 1");

                           try { Thread.sleep(100);} catch (Exception e) {}

                            synchronized (resource2) {
                               System.out.println("Thread 1: locked resource 2");
                           }
                        }
                  }
           };

            // t2 tries to lock resource2 then resource1
           Thread t2 = new Thread() { 

              public void run() {
                synchronized (resource2) {
                   System.out.println("Thread 2: locked resource 2");
                   
                   try { Thread.sleep(100);} catch (Exception e) {}

                            synchronized (resource1) {
                               System.out.println("Thread 2: locked resource 1");
                           } 
                 }
            } ;
         t1.start();
         t2.start();
      }//end of main
   }// end of class

}

2 comments: