Monday, January 9, 2012

Chapter 13: Nested Locks

Imagine a scenario where a synchronized method is calling a non-synchronized method of the same object. In such a situation, the new method has no reason to obtain the lock because; the method calling it already owns the lock.

The reason this works is that Java does not blindly grab the lock when it enters synchronized code. If the current thread owns the lock, there is no reason to wait for the lock to be freed or even to grab the lock. Instead, the code in the synchronized section just executes. Furthermore, the system is smart enough to not free the lock if it did not initially grab it upon entering the synchronized section of code. This works because the system keeps track of the number of recursive acquisitions of the lock, finally freeing the lock upon exiting the first method (or block) that acquired the lock. This functionality is called nested locking.

Yet, it will be a good idea to synchronize methods like this. Are you tempted to ask “Why?”

If you were, think of this scenario. Let’s say another developer makes some new code changes without knowing that this code needs to have the object lock. So, if this developer makes some changes that might affect the way the thread executes or how the locks are acquired, then your code will be messed up big time. That is why I said, it would be a good idea to synchronize those methods as well.

Nested locks are also supported by the ReentrantLock class; the class that implements the Lock interface that we used in the previous chapters. If a lock request is made by the thread that currently owns the lock, the ReentrantLock object just increments an internal count of the number of nested lock requests. Calls to the unlock() method decrement the count. The lock is not freed until the lock count reaches zero. This implementation allows these locks to behave exactly like the synchronized keyword. Note, however, that this is a specific property of the ReentrantLock class and not a general property of classes that implement the Lock interface.

The ReentrantLock classlooks like below:
public class ReentrantLock implements Lock {
public int getHoldCount( );
public boolean isLocked( );
public boolean isHeldByCurrentThread( );
public int getQueueLength( );

The getHoldCount() method returns the number of acquisitions that the current thread has made on the lock. A return value of zero means that the current thread does not own the lock: it does not mean that the lock is free. To determine if the lock is free; not acquired by any thread; the isLocked() method may be used.

Two other methods of the ReentrantLock class are also important to this discussion. The isHeldByCurrentThread() method is used to determine if the thread is owned by the current thread, and the getQueueLength() method can be used to get an estimate of the number of threads waiting to acquire the lock. This value that is returned is only an estimate due to the race condition that exists between the time that the value is calculated and the time that the value is used after it has been returned.

Previous: Choosing a Locking Mechanism

No comments:

Post a Comment

© 2013 by All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.