Topics Covered in the Blog - Synopsis
Showing posts with label java thread locking. Show all posts
Showing posts with label java thread locking. Show all posts
Monday, January 9, 2012
Chapter 12: Choosing a Locking Mechanism
After reading the previous chapters on locks and synchronization, you may be wondering, how would I choose a locking mechanism for my multi-threaded code?
Well, before we answer this doubt, using synchronized methods or blocks is much easier than using the explicit locking mechanism. Using the synchronized keyword, you need not manually grab and release the lock so, the chances of any unexpected exceptions are very minimal (unless your code has a hole through which I can drive a truck, the usage of synchronized keyword does not cause exceptions by itself)
Ok, coming back to the answer, it is possible to use explicit locking for everything. It is possible to code to just use the synchronized keyword. And it is possible to use a combination of both. Avoid using the explicit locking unless you are writing extremely complicate code. In such extreme circumstances, the explicit locking mechanism offers a much better array of features than the standard synchronized keyword. So, the simple answer is “Take a judgment call based on the scenario. If you want to keep it simple, use the Synchronized keyword and for complicated scenarios use explicit locking”
At the end of the day, which technique to use is often a matter of personal preference.
Previous: Lock Scope
Next: Nested Locks
Chapter 11: Lock Scope
Now that we know how object locking works, the next topic to understand is the lock scope. Just like variable scope, locks too have a scope. However, this can be understood only in terms of explicit locking using the concepts we learnt in the previous chapter on “Explicit Locking”
Since the lock() and unlock() method calls are explicit, we can move them anywhere, establishing any lock scope, from a single line of code to a scope that spans multiple methods and objects. By providing the means of specifying the scope of the lock, we can now move time-consuming and threadsafe code outside of the lock scope. And we can now lock at a scope that is specific to the program design instead of the object layout.
To put it simply, the lines of code between the lock() and unlock() methods is the scope of the lock that is being acquired.
Synchronized Blocks
It is possible for the synchronized keyword to lock a block of code within a method. It is also possible for the synchronized keyword to specify the object whose lock is grabbed instead of using the lock of the object that contains the method. Much of what we accomplish with the Lock interface can still be done with the synchronized keyword. It is possible to lock at a scope that is smaller than a method, and it is possible to create an object just so that it can be used as an synchronization object.
A Synchronized Block would look like below:
// lots of code
synchronized(this) {
// Code to be synchronized
}
// lots more code
This syntax of the synchronized keyword requires an object whose lock is obtained. Here we are using the this object. Using this syntax, we can now lock individual lines of code instead of the whole method. We can also share data across multiple objects by locking on other objects instead, such as the data object to be shared.
After reading this chapter, you may be wondering “How different are Synchronized Methods from Synchronized Blocks?”
Well, the answer my friend is that, a synchronized method and block work the same way. The scope of the lock is the only difference. Using synchronized blocks, we can implement synchronization at a higher/granular level for only a few lines of code instead of the whole method. Apart from this, they work in exactly the same way.
Previous: Explicit Locking
Next: Choosing a Locking Mechanism
Chapter 10: Explicit Locking of Objects
In the previous chapters we learnt about the “Synchronized Keyword” and how the whole “Synchronization & Race Condition” concept works. To recap, the purpose of the synchronized keyword is to provide the ability to allow serialized entrance to synchronized methods in an object. Although almost all the needs of data protection can be accomplished with this keyword, it is too primitive when the need for complex synchronization arises. More complex cases can be handled by using classes that achieve similar functionality as the synchronized keyword.
Using the Synchronized keyword automatically captures & releases locks when threads execute. But, starting J2SE 5.0, a developer can explicitly capture and release locks on objects. Sounds cool doesn’t it? This is exactly what we are going to learn in this chapter.
The synchronization tools in J2SE 5.0 implement a common interface: the Lock interface. For this chapter, the two methods of this interface that are important to us are lock( ) and unlock(). Using the Lock interface is similar to using the synchronized keyword: we call the lock() method at the start of the method and call the unlock() method at the end of the method, and we've effectively synchronized the method.
The lock() method grabs the lock. The difference is that the lock can now be more easily envisioned, we now have an actual object that represents the lock. This object can be stored, passed around, and even discarded. As before, if another thread owns the lock, a thread that attempts to acquire the lock waits until the other thread calls the unlock() method of the lock. Once that happens, the waiting thread grabs the lock and returns from the lock( ) method. If another thread then wants the lock, it has to wait until the current thread calls the unlock() method.
In terms of functionality, the code works exactly the same way as it would work with the Synchronized keyword. But, there is a minor difference. The difference is that by using a lock class, we can now utilize other functionality, that can't be accomplished by just using the synchronized keyword.
Using a lock class, we can now grab and release a lock whenever desired. We can test conditions before grabbing or releasing the lock. And since the lock is no longer attached to the object whose method is being called, it is now possible for two objects to share the same lock. It is also possible for one object to have multiple locks. Locks can be attached to data, groups of data, or anything else, instead of just the objects that contain the executing methods.
This is the cool advantage of using “Explicit Locking”.
The Lock Interface
Before we wrap up this chapter, let's look a little deeper into the Lock interface. The Lock interface code would look like below:
public interface Lock {
void lock( );
void lockInterruptibly( ) throws InterruptedException;
boolean tryLock( );
boolean tryLock(long time, TimeUnit unit)
throws InterruptedException;
void unlock( );
Condition newCondition( );
}
Lets understand the key methods of this class that we will use in real life:
• lock() – this is the method you will use to obtain the lock. If the lock is not available, it waits until the lock is available.
• tryLock() – this method is similar to the lock() method but, if the lock is not available, it does not wait and returns a boolean value of false. If the lock is obtained, it returns true
• tryLock(long time, TimeUnit unit) – this method is similar to the tryLock() method with a small difference. You can specify the time period that this method has to wait, in case a lock is not available right away. The time passed as argument is the maximum time this method will wait for the lock
• unlock() – this method is used to release/relenquish the lock
Previous: Race Conditions
Next: Lock Scope
Subscribe to:
Posts (Atom)
© 2013 by www.inheritingjava.blogspot.com. 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.

