Tuesday, February 24, 2015

The Lock implementations in Java are more flexible than using synchronized methods and statements. They support quite different properties and multiple Condition objects. The Lock interface has the following structure:

The implementation classes for Lock provide additional functionality over synchronized methods and statements e.g. non-blocking or optimistic attempt to acquire a lock using tryLock(), attempt to acquire the lock that can be interrupted (lockInterruptibly()), and attempt to acquire a lock that can timeout (tryLock(long, TimeUnit)). A Lock class can also provide behavior quite different from implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection.

Another interface related to locking is ReadWriteLock which has the following structure:

public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}

As per the Java Doc:

A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.

It provided more flexibility as it exploits the fact that only a single thread can modify whereas multiple threads can read at same time. The actual performance depends upon frequency of read-writes, duration of each operation, and the contention for the data i.e. no of threads that will try to read-write the data at same time.

New Request is for?

Other thread is already reading

Other thread is already writing

Read

Good to go.

Stop and wait.

Write

Stop and wait.

Stop and wait.

The implementation classes for these interfaces are given below:Lock: ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLockReadWriteLock:ReentrantReadWriteLock

Although the basic operation of a read-write lock is straight-forward, there are many policy decisions that an implementation must make:

When both readers and writers are waiting whether to grant read or write lock?

Whether readers that request the read lock while a reader is active and a writer is waiting, are granted the read lock.

Whether the locks are reentrant: can a thread with the write lock reacquire it? Can it acquire a read lock while holding the write lock? Is the read lock itself reentrant?

Can the write lock be downgraded to a read lock without allowing an intervening writer? Can a read lock be upgraded to a write lock?

ReentrantLock
If a thread invokes lock() and does not own the lock then it will successfully acquire the lock and method will return.The method will return immediately if the current thread already owns the lock. This can be checked using methods isHeldByCurrentThread(), and getHoldCount(). In the following example we have two methods that will be invoked by two different threads, but each method will increment the count.

Can you guess the output? If you have noticed there is one method in Lock interface newCondition() which returns a Condition object. Conditions provide a means for one thread to suspend execution until notified by another thread that some state condition may now be true. Lets take another example:

There was some problem with read-write lock in JDK 5 where multiple readers executing concurrently in critical section can lock all writer threads. In JDK 6 this problem was resolved but then readers seem to be starved. You can read more about this here.

StampedLock
Another related class is StampedLock which has three modes for controlling read/write access. The state of a StampedLock consists of a version and mode. Lock acquisition methods return a stamp that represents and controls access with respect to a lock state. The "try" versions may return the special value zero to represent failure to acquire access. The modes are:

Writing. Method writeLock() possibly blocks waiting for exclusive access, returning a stamp that can be used in method unlockWrite(long) to release the lock. Untimed and timed versions of tryWriteLock are also provided. When the lock is held in write mode, no read locks may be obtained, and all optimistic read validations will fail.

Reading. Method readLock() possibly blocks waiting for non-exclusive access, returning a stamp that can be used in method unlockRead(long) to release the lock. Untimed and timed versions of tryReadLock are also provided.

Optimistic Reading. Method tryOptimisticRead() returns a non-zero stamp only if the lock is not currently held in write mode. Method validate(long) returns true if the lock has not been acquired in write mode since obtaining a given stamp. This mode can be thought of as an extremely weak version of a read-lock, that can be broken by a writer at any time. The use of optimistic mode for short read-only code segments often reduces contention and improves throughput. However, its use is inherently fragile. Optimistic read sections should only read fields and hold them in local variables for later use after validation.

In the above method after trying for optimistic read lock (using tryOptimisticRead) we need to validate the stamp to ensure everything is OK. If the stamp does not validate it means a write has acquired the lock in between and the values we have may be stale. So we again acquire the read lock but this time it is pessimistic and after getting it we assign the values and then compute the method.

Monday, February 23, 2015

CountDownLatch is a synchronizer that allows one or more threads to wait until a set of operations being performed in other threads completes. A CDL is initialized with a given count which specifies the number of parties involved. Whenever the method countDown() is called it decrements the value of count by one.

Generally a CDL is used when one or more threads are supposed to wait for a number of threads (parties) to finish. In that case waiting threads make use of await methods
which block until the count reaches zero, on other hand each party decrements the count whenever it finishes. When count is zero all waiting threads are released
and any subsequent invocations of await return immediately.

Unlike CyclicBarrier it is non-cyclic. If we need a version that resets the count then we should consider using a CyclicBarrier. A useful property of a CountDownLatch is that it doesn't require that threads calling countDown wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past an await until all threads could pass.