Enrich the Lock interface

David Holmes david.holmes at oracle.com
Tue Aug 22 05:21:51 UTC 2023


On 21/08/2023 11:56 pm, Albert Attard wrote:
> Hello.
> 
> Thank you very much Pavel for helping me find more information about this.
> 
> After some research (mainly by Pavel) we found a thread, with subject 
> "/Default Functions for Lock Interface/", from October 2013 that 
> discussed this exact thing.  I don't believe that this thread is 
> available on the internet, but I may be wrong.
> 
> In this thread, two approaches were discussed.
> 
>  1. Add support for the try-with-resources
>  2. Add default methods to the Lock interface
> 
> 
> The second approach makes use of lambda functions which incur 
> performance cost when data is modified within the lambda function, as 
> described by Brian Goetz in the same thread (on the 8th of October 2013).
> 
> ---
> /When you write a method like
> 
> void withLock(Runnable)
> 
> the Runnable is going to have side-effects. So its going to be a 
> capturing lambda -- one that captures variables from its scope:
> 
> withLock( () -> { counter++; } ); // counter is captured
> 
> With the current implementation of lambda, evaluating (not invoking) a 
> capturing lambda expression will cause an allocation. Whereas the 
> hand-unrolled version:
> 
> lock.lock();
> try { counter++; }
> finally { lock.unlock(); }
> 
> does not. The sort of things people do with locks are generally pretty 
> performance-sensitive, so such an API was deemed, at the current time, 
> to be an "attractive nuisance."
> /---
> 
> Almost 10 years have passed since this was originally suggested.  Have 
> enough things changed since then, that would make this approach feasible?

Long before lambda's Doug Lea originally had this in the form of 
LockedExecutor:

https://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/LockedExecutor.html

but it never made the cut into java.util.concurrent (JSR-166).

A "withLock" style of programming does have some appeal to some people 
but it was never considered worthy of a place in the core API. The basic 
thing is trivial but then there are issues about returning values, or 
specialized exception handling - all of which are best handled, and 
easily handled, by application logic.

Cheers,
David
-----

> With kind regards,
> Albert Attard
> 
> 
> On Mon, 21 Aug 2023 at 15:33, John Hendrikx <john.hendrikx at gmail.com 
> <mailto:john.hendrikx at gmail.com>> wrote:
> 
>     I couldn't find a discussion on openjdk, but for those interested (and
>     to save others some searching) there is a JBS ticket:
> 
>     https://bugs.openjdk.org/browse/JDK-8025597
>     <https://bugs.openjdk.org/browse/JDK-8025597>
> 
>     --John
> 
>     On 21/08/2023 14:37, Pavel Rappo wrote:
>      > This is suggested every once in a while. I appreciate that
>     openjdk mailing lists are not easily searchable, but with a bit of
>     skill, you could find a few previous discussions on the topic.
>      >
>      > This has also been discussed on concurrency-interest (at
>     cs.oswego.edu <http://cs.oswego.edu> <http://cs.oswego.edu/
>     <http://cs.oswego.edu/>>), a dedicated mailing list for concurrency
>     in Java. Sadly, that list has been defunct for quite some time now.
>      >
>      > -Pavel
>      >
>      >> On 21 Aug 2023, at 13:18, Albert Attard <albertattard at gmail.com
>     <mailto:albertattard at gmail.com>> wrote:
>      >>
>      >> Hello.
>      >>
>      >> I hope all is well.
>      >>
>      >> Do you believe it is a bad idea to enrich the Lock interface
>     with a set of default methods that safely release the lock once ready?
>      >>
>      >> Consider the following (dangerous) example.
>      >>
>      >> final Lock lock = new ReentrantLock ();
>      >> lock.lock();
>      >> /* Code that may throw an exception */
>      >> lock.unlock();
>      >>
>      >> This example will never release the lock if an exception is
>     thrown, as the programmer didn’t wrap this up in a try/finally.
>      >>
>      >> Adding a default method within the Lock interface, called
>     withLock(Runnable) for example or any better name, would streamline
>     this, as shown next.
>      >>
>      >> default void withLock(final Runnable runnable) {
>      >>      requireNonNull(runnable, "Cannot run a null");
>      >>      lock();
>      >>      try {
>      >>          runnable.run();
>      >>      } finally {
>      >>          unlock();
>      >>      }
>      >> }
>      >>
>      >> The caller can now simply change the above example into the
>     following, without having to worry about this.
>      >>
>      >> final Lock lock = new ReentrantLock ();
>      >> lock.withLock(() -> {
>      >>    /* Code that may throw an exception */
>      >> });
>      >>
>      >> We can have more variants of these default methods, as shown next.
>      >>
>      >> default <T> T getWithLock(final Supplier<T> supplier) {
>      >>      requireNonNull(supplier, "The supplier cannot be null");
>      >>      lock();
>      >>      try {
>      >>          return supplier.get();
>      >>      } finally {
>      >>          unlock();
>      >>      }
>      >> }
>      >>
>      >> Any thoughts?
>      >>
>      >> With kind regards,
>      >> Albert Attard
> 


More information about the core-libs-dev mailing list