Reputation: 2049
A Lock is always followed by a try/finally block, why?
ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
Lock read = readWriteLockBitmap.readLock();
Lock write = readWriteLockBitmap.writeLock();
int shared = 0;
public void function1(){
read.lock();
try{
//reading shared int
}
finally{
read.unlock();
}
}
public void function 2(){
write.lock();
try{
//modify shared int
}
finally{
write.unlock();
}
}
Why having this try/finally block and not simply writing the code as follows:
ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
Lock read = readWriteLockBitmap.readLock();
Lock write = readWriteLockBitmap.writeLock();
int shared = 0;
public void function1(){
read.lock();
//reading shared int
read.unlock();
}
public void function 2(){
write.lock();
//modify shared int
write.unlock();
}
Upvotes: 7
Views: 7575
Reputation: 128899
So that something like this doesn't happen:
private static ReentrantReadWriteLock readWriteLockBitmap = new ReentrantReadWriteLock();
private static Lock read = readWriteLockBitmap.readLock();
private static Lock write = readWriteLockBitmap.writeLock();
private static int shared = 0;
public static void function1() {
read.lock();
somethingThatMightThrowAnException();
read.unlock();
}
private static void somethingThatMightThrowAnException() {
throw new RuntimeException("I'm a bad man.");
}
public static void function2() {
write.lock();
//modify shared int
write.unlock();
}
public static void main(String[] args) {
try {
function1();
} catch (Exception e) {
System.out.println("Got an exception, but so what?");
}
function2();
}
Upvotes: 6
Reputation: 11162
Because a try/finally block is the only way to guarantee that a segment of code is executed after another completes.
You ask why not do this:
public void function1(){
read.lock();
this.getSharedInt();
read.unlock();
}
What happens when this.getSharedInt()
throws an exception? Then your read.unlock()
line will not be executed, causing program deadlock. Sure, it may be 100% certified to not throw an exception right now, but what happens when you refactor to store that shared int in a file or database?
Finally, don't forget that try/finally also accounts for errors, which can be thrown by the runtime at almost any line in a program, even if the function is guaranteed to not throw any exceptions.
Note that this code would also work, but it swallows the exception. Using finally
instead allows the exception to propagate normally, while still unlocking under all conditions.
public void function2(){
read.lock();
try {
this.getSharedInt();
} catch(Throwable t) {}
read.unlock();
}
Upvotes: 11
Reputation: 1526
First hit is: http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/locks/Lock.html
Quoting the key part:
In most cases, the following idiom should be used:
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.
Upvotes: 1
Reputation: 18143
The issue isn't that you need the try block. The point is to ensure that if you're app throws an exception of any sort that the unlock is still called. Otherwise, the lock would stay locked.
Upvotes: 3
Reputation: 137382
To make sure that whatever happens, even if an exception is thrown, you will still unlock the locked stream before leaving the method.
Upvotes: 2
Reputation: 55223
In case anything goes wrong (Exception being thrown etc.) you want to make sure the lock is released no matter what. It's just standard practice, even though in this case may technically be unnecessary.
Upvotes: 6