Ben Evans (@kittylyst) and Martijn Verburg (@karianna) have teamed up to write "The Well-Grounded Java Developer" (Covers Java 7 and Polyglot programming on the JVM). You can find their joint account on twitter (@java7developer). Ben has been a professional developer and Open Source enthusiast since the late 90s. He has delivered world-class projects for banks, media companies and charities in that time, and currently works as an architect, lead developer and in-house Java expert at one of the world’s leading financial institutions. Martijn Verburg is a Java/JEE and open source consultant who is passionate about software craftsmanship and the creative power of technical communities. He currently is the co-leader for the London JUG, runs two open source projects (PCGen and Ikasan EIP) and is a bartender at the Javaranch. Martijn & Ben has posted 6 posts at DZone. View Full User Profile

Project Coin: the try-with-resources lock support debate

03.29.2011
| 4194 views |
  • submit to reddit

If you have recently been following Project Coin’s mailing list , you will have spotted an interesting discussion regarding the inclusion of lock management inside the scope of a try-with-resources (TWR) code block.

The Initial Idea

The idea was initiated by Gernot Neppert who proposed a class java.util.concurrent.AutoLockable which would implement AutoCloseable, and therefore be eligible for usage with TWR:

package java.util.concurrent.locks;

public abstract class AutoLockable implements AutoCloseable
{
public static AutoLockable locked(final Lock lock)
{
lock.lock();
return new AutoLockable()
{
@Override
public void close() {
lock.unlock();
}
};
}

public abstract void close();
}

Its usage would be something like this:

try(AutoLockable locked = AutoLockable.locked(lock))
{
// Do something in locked scope
}

This proposed idea certainly has merit, however the sharp eyed amongst you will notice a performance issue in creating a new object each time you perform a lock. Additionally, you would also have to have an extra method to acquire the lock (the locked(...) method in the above example). So what else could be tried?

An Alternative Idea

Dr Heinz M. Kabutz posted a link to a newsletter where he describes an interesting way of using JDK 7′s TWR to automatically unlock Java 5 locks. Long story short, the main idea is to build a wrapper class around a Lock, which implements AutoCloseable and manually unlocks in the close() method. The wrapper along with usage of static imports would bring verbose code like:

lock.lock();
try
{
printLockStatus();
}
finally
{
lock.unlock();
}

… to a more readable form:

try (lock(lock))
{
printLockStatus();
}

However, as the author himself mentioned, the problem of creating extra objects every time you perform a lock still remains. Moreover, as David Holmes signaled in the mailing list, the spec has been updated to prohibit usage of resources as general expressions in the TWR argument and only allow passing them with an accompanying explicit variable declaration.

Why TWR (as it stands) can’t support this

Among the reasons for this update were difficulties encountered by the parser which was not always able to distinguish between the start of an expression and the start of a type:

try(i < j // Ternary operator on variables i and j
? new Resource1() :
new Resource2()) {...}

… compared to code like

try(Box < Resource // Simple generic wrapper around a resource
> resourceBox = Box<>(new Resource1())) {...}

Another reason for change was the use case of managing an existing variable which changes its value inside the try block. The example presented on the update site is the following:

public class TwrExamples implements AutoCloseable
{
public static void main(String... args)
{
TwrExamples twrEg1 = new TwrExamples();
System.out.println(twrEg1.hashCode());

try(twrEg1)
{
twrEg1 = new TwrExamples(); // Mutating the variable!
System.out.println(twrEg1.hashCode());
}
}

@Override
public void close()
{
System.out.println(hashCode());
}
}

.. where close() will be called on the first twrEg1 instance, not on the one pointed to at the time the try block finishes. Thus, output results after running a TWR having a TwrExamples resource as argument, may look like this:

1607576787
1051296202
1607576787

The documentation of the Project Coin features posted on March 1st 2011 by Joe Darcy further strengthens the rule of requiring variables to declare a resource in detriment of using general expressions:

“A resource specification declares one or more local variables; the type of each variable must be a subtype of AutoCloseable or a compile-time error occurs.”

However, assigning a new variable to an already existing one referring to the lock just because TWR prohibits identifiers seems troublesome. There is a section in the JSR 334 spec changelog stating that:

“One potential future extension is to allow a resource to be specified as an expression that is a final or effectively final variable. Such a restricted expression form would remove the need to declare a resource variable for the sole purpose of aliasing an existing variable while avoiding pathologies stemming from the resource variable being modified within the body of the |try|-with-resources statement.”

Joe Darcy states in the mailing list that even though this change is too late to be applied to JDK 7, it would be a nice addition to JDK 8.

Some Extra Analysis

Another heads-up in this direction is related to constructs such as try (Resource r = getResource()), where methods such as getResource() are not expected to fail. Some workarounds are proposed by Reinier Zwitserloot in coin-dev, for example not considering the expression Resource r = getResource() as part of the try, and do something like this try (Resource r = ...) { try { ..... }} . Another solution would be setting r to null if the exception that triggers the catch block is resulted from getResource() method. The example from the mailing list is :

try (Resource r = getResource())
{
/*.... */
}
catch (Exception e)
{
icon = Icons.DEFAULT_ICON;
logger.log("App icon resource " + r.getURL() + " is not available", e);
}

In this case we would prefer obtaining a NullPointerException in the log, rather than a core dump.

Your Thoughts?

We’re curious to find out any opinions the readers of this blog might have regarding this ongoing topic discussion on coin-dev. Do you think automatic TWR lock support might be useful to you?

 

From http://www.java7developer.com/blog/?p=256

Published at DZone with permission of its author, Martijn & Ben Verburg & Evans.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Shoaib Almas replied on Sat, 2012/08/25 - 6:01am

But instead of a method generating a new object for each lock, could you use pooling to avoid that much obejct creation? You’d return the instance on Autocloseable.close() to the pool, create more objects when needed?

Java Forum

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.