• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Reentrant Locks

 
Greenhorn
Posts: 17
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator




I want to know why is it not appropriate to place the lock.lock() inside the try block? and why we use try finally block instead of using try catch finally block?

Thanks.
 
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is the whole pattern:

What would you achieve by putting the lock() call inside of the try-clause? What would happen if the lock failed?

Whether or not to use a catch-clause depends on what the purpose and responsibilities are of the method containing the try. There is no general rule.
 
Akshay Rathore
Greenhorn
Posts: 17
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Even if the lock.lock() is not inside the try block it could fail right? so its better to put it inside try and catch the exception if thrown.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First of all, you shouldn't always catch exceptions immediately. In some cases, you may want to propagate the exception to the next layer of the application. That's a different discussion though.

If you want to catch an exception from a lock statement, you should do it like this:

The reason is that locks shouldn't be locked within their own critical sections. Why not? Take another look at the piece of code I wrote in my first post. What happens when you lock the lock within the try-clause, and an exception occurs?
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Akshay Rathore wrote:Even if the lock.lock() is not inside the try block it could fail right?


Not normally (the method isn't declared to throw any exceptions).

And if it does, what do you propose to do about it? The whole point of lock.lock() is that it blocks until the lock can be acquired, so it's far more likely to block forever due to some bug in your locking logic than throw an exception.

My advice: Use the method exactly the way the docs tell you to (which is what Stephan posted).

Winston
 
Akshay Rathore
Greenhorn
Posts: 17
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the reply.
 
author
Posts: 4335
39
jQuery Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jeanne and I actually discussed this in detail when creating the OCP 8 Upgrade Appendix (see sidebar on page 608 of our OCP 8 book). The Oracle ReentrantLock JavaDoc puts lock() outside the try {} block, but both of us having a strong database background this "felt" wrong. It would be like opening a database connection outside the try {} block, but still releasing it in a finally {} block.

The general design principle for resource handling (locks and database connections both being resources) is to always 'open' the connection in a try {} block and attempt to release it in a finally {} block.

The big thing to be concerned about is if lock() throws an exception that allows an incomplete lock to be acquired. It may be the case that the JVM ReentrantLock is incapable of both throwing an exception and acquiring a lock at the same time, but that doesn't mean other Lock are incapable of doing this. Therefore, putting it inside the try {} block means your code will be more robust if you use a different Lock implementation (remember Lock is an interface so you could use other types).
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Scott, I would assume that the relevant resource (be it a lock or a DB connection) is only acquired successfully when the method call returns without an exception. That means that acquiring it inside the critical section can cause the finally-clause to attempt to release the resource even if it has not been acquired successfully. This shouldn't be a big problem for locks and connections in general (I assume unlock()/close() operations are idempotent) but may have disastrous results for similar resources:
 
Scott Selikoff
author
Posts: 4335
39
jQuery Eclipse IDE Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That depends on the particular resource implementation. For example, in JDBC calling close() on a connection you are finished with is always recommended even if the connection threw an exception.

For locks, the procedure is a little different due to the fact that the lock is often shared among multiple threads. For example, you don't want to unlock something that you never acquired the lock for. For this, you need to manage how many locks you aquired using a local variable. For example, tryLock() only returns true if the lock was acquired, so in the false case you do not need to release it.

As for whether or not you should release a lock acquired through a lock() method (void return type) that threw an exception, that depends on the implementation and under what situations an exception would commonly be thrown.
 
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Does Lock#lock() ever throw any Exceptions? That link on the left suggests it is permissible to throw an unchecked Exception but ReentrantLock#lock() doesn't say anything about Exceptions.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Scott Selikoff wrote:but both of us having a strong database background this "felt" wrong. It would be like opening a database connection outside the try {} block, but still releasing it in a finally {} block.


As someone with a fair background in db's myself, I have to disagree. A lock is infinitely less involved than a database connection, which is designed to connect with a database, and could fail for any number of reasons.

A lock is a semaphore (or token), generated in the same JVM as the running program, whose sole purpose in life is to tell YOU if you have exclusive control of something protected by the lock.
My wonder - assuming it's always used correctly - is why you need a try block at all ... but I sort of understand the reasons.

Winston
 
Scott Selikoff
author
Posts: 4335
39
jQuery Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Because you can't have a finally without a try {} block. And you absolutely need a finally {} block anytime to you ownership of a resource (db or lock) to ensure that you don't enter a deadlock state where a resource is taken but never released.

Anytime I see the words "resource leak" (or connections exhausted) and "database" in the same sentence, it's almost always caused by a developer acquiring a resource and never letting go of it due to 'unexpected' behavior. The point of finally block {} is to ensure an attempt to release the resource is always made.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Scott Selikoff wrote:Because you can't have a finally without a try {} block.


Then perhaps that's the problem. Or maybe we need a "resource" or "lock" block that doesn't impose all the draconian stuff like flushing and "happens before" that try does.

The fact of the matter is that we have a piece of code that we want protected, and we have something called a "Lock" - an interface and a set of classes that were created specifically because synchronized was deemed too slow in high-contention situations.

Personally, I would like to have seen a Lock as an object rather like Runtime - ie, a container for the method (or methods) you want to run. No trys, no finallys - just call the method, and have the class release whatever it has to on completion. It could have been easily (albeit clunkily) done before version 8, and I suspect it's even easier now.

Winston
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic