Source

In concurrent programming, we need to focus on two things

Mutual exclusion

When a process/thread is executing its critical section no other processes are allowed to execute their critical section. (Each process has a code segment called “Critical section” in which shared data is accessed.)

Synchronisation

When threads are trying to achieve a common goal via working together, these threads need cooperation between them. They need to synchronize when they focus on a common goal.

Monitors are used to achieve mutual exclusion and synchronization.

How to understand Monitor easily?

  • The monitor enforces mutual exclusive access to synchronized methods invoked on the associated object.
  • Don’t confuse this critical area with the critical section since here, the Critical area mentioned in the object-level, not for the thread level. The shared data is considered as a critical area.

Each object and its class are associated with a monitor.

  • Each object and its class are associated with a monitor.
  • When a thread calls a synchronized method on an object, the JVM checks the monitor for that object
  • Instance variables of objects that needed to be protected from concurrent access comprised a critical area for a monitor associated with the object, and instance variables of classes/static variables of a class that needed to be protected from concurrent access included a critical area for the monitor associated with the class.

If the monitor is unowned, ownership is assigned to the calling thread, which is then allowed to proceed with the method call

if the monitor is owned by another thread, the calling thread will be put on hold until the monitor becomes available

  • 🎯 This critical area is protected with a lock and this lock ensures mutual exclusion.
  • 🎯 A Wait set is also associated with a monitor that is used to provide coordination between threads.
  • 🎯 An entry set is used to hold the threads who are already requested for the lock and the lock is not acquired by them yet.

How is mutual exclusion achieved on Monitor?

  • Each object is associated with a monitor and this monitor has a lock where each thread can lock or unlock the object using this lock when it accesses the shared variables.
  • Explicitly, it means only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that lock are blocked until they can obtain the lock. when a new thread tries to acquire the lock and if already a thread owns the lock then that thread will be waiting on the entry set to acquire the lock. when the thread which is acquired the lock completes its critical section, it will release the lock. So next thread will acquire the lock but this next thread is taken from the entry set and will be determined by JVM based on some criteria like FIFO.
  • Here, what we achieved is mutual exclusion since we give exclusive access to a thread to the object and we do not allow any other threads to enter their critical section.

Example java code to achieve mutual exclusion using monitor

class Counter
{
private int count = 0;
public void synchronized Increment() {
int n = count;
count = n+1;
} //Here synchronized is used to indicate those things should be done sequentially.
}

How is coordination/synchronization achieved via Monitor?

Synchronization is important when one thread needs some data to be in a particular state and another thread is responsible for getting the data into that state e.g. producer/consumer problem

  • Synchronization is achieved using the wait set which is associated with the monitor and “wait and notify” or “signal and continue” mechanism.
  • Synchronization is important when one thread needs some data to be in a particular state and another thread is responsible for getting the data into that state e.g. producer/consumer problem
  • When a thread calls the wait() method respect to object then the thread suspended and added to the wait set to wait until some other thread invokes notify() or notifyAll() on the same object.
  • The notify() method is used for waking up threads that are in the wait set of the monitor of a particular object. There are two ways of notifying waiting threads.
  • The wait() method suspends the calling thread and temporarily releases ownership of the monitor (so it allows other threads to acquire the monitor). The suspended thread that called wait() wakes up only when another thread calls notify() or notifyAll() on that object.
  • 🎯 notify() → For all threads waiting on wait set the method notify() notifies anyone of them to wake up arbitrarily. The choice of exactly which thread to wake is non-deterministic and depends upon the JVM.
  • 🎯 notifyAll() → This method simply wakes all threads that are waiting on the wait set. The awakened threads will not be able to proceed until the current thread releases the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize. One thread gets it, and the others go back to waiting.

Example java code to achive synchronization using monitor in producer consumer problem

class Buffer {
private char [] buffer;
private int count = 0, in = 0, out = 0;

Buffer(int size)
{
buffer = new char[size];
}

public synchronized void Put(char c) {
while(count == buffer.length)
{
try { wait(); }
catch (InterruptedException e) { }
finally { }
}
System.out.println("Producing " + c + " ...");
buffer[in] = c;
in = (in + 1) % buffer.length;
count++;
notify();
}

public synchronized char Get() {
while (count == 0)
{
try { wait(); }
catch (InterruptedException e) { }
finally { }
}
char c = buffer[out];
out = (out + 1) % buffer.length;
count--;
System.out.println("Consuming " + c + " ...");
notify();
return c;
}
}

To summarize:

  1. If a class has one or more synchronized methods, each object of the class gets a queue that holds all threads waiting to execute one of theng the synchronized methods.
  2. There two ways for a thread to get onto this queue, either by calling the method while another thread is using the object or by calling wait(), while using the object.
  3. When a synchronized method call returns, or when a method calls wait(), another thread gets access to the object.
  4. If a thread was put in the queue by a call to wait(), it must be “unfrozen” by a call to notify() before it can be scheduled for execution again.

The synchronization rules are complex, but it is actually quite simple to put them into practice. Just follow these rules:

  1. If two or more threads modify an object, declare the methods that carry out the modification as synchronized.
  2. If a thread must wait for the state of an object to change, it should wait inside the object, not outside, by entering the synchronized method and calling wait().
  3. Whenever a method changes the state of an object, it should call notify(). That gives the waiting threads a chance to see if circumstances have changed.

These concepts are emphasized in this advanced threads tutorial, take a look in case things are still blurry for you.

--

--

No responses yet