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

6 Comments

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?

Did you like this? Share it:

Getting started with JDK7

8 Comments

We are all aware that the next version of Java is about to make its flashy entrance this July; We’ve seen the list of features it brings to the table and we are nothing less than anxious to take the JDK for a “test drive”. So why not do just that?

Even though the current build (127 at the time this post was written) is available for download, we must take into account that it is still under development, so don’t expect the binaries you download now to provide the same functionality and stability as the stable release which we will get to see in summer. However, you have an opportunity to get an early impression of how the new Java version will behave at your fingertips and you should definitely take advantage of it. Moreover, if you want to track the progress of the various projects composing JDK 7, you may want to subscribe to their mailing lists.

On January 13th 2011, Mark Reinhold – chief architect of the Java Platform Group at Oracle – announced on the jdk7-dev mailing list: “The JDK 7 Project has reached a major milestone: It is Feature-Complete. This means that all of the planned features have been implemented and integrated into the master forest, along with their unit tests, and all other planned tests have been written and run on a representative set of platforms”.

Without further ado, below is a step-by-step detailed description of downloading and setting up the latest JDK 7 build (for Debian/Windows/MacOS X) on your machine.

Debian

1. Download binaries from http://download.java.net/openjdk/jdk7/

Alternatively, open a terminal and type:

  • for 32 bit OS:
    wget http://www.java.net/download/jdk7/archive/b125/binaries/jdk-7-ea-bin-b125-linux-i586-13_jan_2011.bin
  • for 64 bit OS:
    wget http://www.java.net/download/jdk7/archive/b125/binaries/jdk-7-ea-bin-b125-linux-x64-13_jan_2011.bin

2. Run the previously downloaded self-extracting .bin file (first make sure you have executing permissions by chmodding those files to have +x access), by typing in the command line:

  • for 32 bit OS
    ./jdk-7-ea-bin-b125-linux-i586-13_jan_2011.bin
  • for 64 bit OS
    ./jdk-7-ea-bin-b125-linux-x64-13_jan_2011.bin

Accept the license agreement by writing “yes” in the command line and the JDK 7 will unpack itself in the same folder as the .bin file . You are required to press “enter” to finish unpacking.

3. Move the newly unpacked jdk1.7.0 folder to the /opt/jvm/ folder – creating /opt/jvm folder first:

sudo mkdir /opt/jvm ; sudo mv jdk1.7.0 /opt/jvm

If you have more than one JDK’s installed, type:

sudo update-alternatives –-config java.

This will get you a list of the installed JDK’s and their indexes. To install JDK 7 you just type:

sudo update-alternatives –-install /usr/bin/java java /opt/jvm/jdk1.7.0/jre/bin/java 2

where 2 is the next unused index from the previous command.  This should be repeated for javac and javadoc if you are going to use them via the command line. Finally check that the proper Java is installed by typing:

java -version

Windows

  1. Download binaries from: http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html
  2. Run the downloaded .exe file and go through the installation wizard, we recommend installing it to “C:\Java\jdk1.7.0_build<x>”
  3. Set JAVA_HOME & PATH environment variables: In the command line write:set JAVA_HOME=”C:\Java\jdk1.7.0″
    set PATH=C:\Java\jdk1.7.0\bin;%PATH%

NOTE: GUIs for setting path variables can be found here:

4. [OPTIONAL]run java -version & javac -version to check that they point to the correct jdk version

MacOS X

On 12 January 2011, Richard Mayhew wrote an article on The Server Side about the MacOS and JDK 7 tandem. He stated the following: “Just in case you didn’t know: wikis.sun.com has directions for building OpenJDK7 for MacOS. Also, code.google.com has a prebuilt JDK7 for 32-bit and 64-bit MacOS.” Following the links provided in this article you will be able to set up JDK 7 on your Mac OS.

You are now ready to start juggling with the new features which JDK 7 has to offer. You may test your code in your favourite text editor, or perhaps you wish to try Netbeans 7.0 Beta IDE which introduces language support for development to the Java SE 7 specification with the JDK 7 platform.

Enjoy!  Dragos (our fantastic intern!), John, Ben & Martijn

Did you like this? Share it:

Java 7’s Automatic Resource Management now covers JDBC

6 Comments

One of the most eye-catching new features of Java 7’s Project Coin (JSR Pending) is Automatic Resource Management (ARM). ARM removes the need to write exception handling and resource management code for I/O streams, socket connections and other resources. In other words, there will no longer be a need to write error-prone try/catch statements, nor tedious resource cleanup code.

As stated on Joseph D. Darcy’s Oracle Weblog, ARM support is to be added to JDBC, which will provide much relief to ORM providers and day to developers alike!

This blog entry will highlight the benefits of ARM via a basic I/O based code example and will then go one to show a similar example for JDBC.

Lets imagine you’ve been asked to read a file containing the names of the New Zealand Football squad, and print those names out line by line. The existing (JDK 6) way of writing this code would probably look a little something like this:

FileReader fr;
BufferedReader br;
try
{
    String teamMember;
    fr = new FileReader('/home/NZTeamList.txt');
    br = new BufferedReader(fr);
    while ((teamMember = br.readLine()) != null)
    {
        System.out.println(teamMember);
    }
}
catch (FileNotFoundException e)
{
    e.printStackTrace();
}
catch (IOException e)
{
    e.printStackTrace();
}
finally
{
    if (br!= null)
    {
        br.close();
        if (fr != null)
        {
            fr.close();
        }
    }
}

As well as making sure that you cleanly close of the BufferedReader and the FileReader, notice all of the extra try/catch exception handling you have to put in place. It would be all to easy to miss a close() call or to declare a catch incorrectly.

Now lets look at the same problem with ARM involved. ARM removes the need for the explicit exception handling and automatically closes off resources for you:

String teamMember = null;
try (BufferedReader br =
            new BufferedReader(new FileReader('/home/NZTeamList.txt')))
{
    while ((teamMember = br.readLine()) != null)
    {
        System.out.println(teamMember);
    }
}

Notice the new syntax – the resources which will be managed are now inside a try()
parenthesis and the exception handling (i.e. the ‘catch’ blocks) is gone. The logic is now much cleaner and focused purely on the task at hand, no extra code for resource management is required.

You might be asking yourself: “Does that work for any manageable resource in the Java Standard Edition?” and the answer would be “No…. for now”. But a large step in the right direction has been made with the announcement that JDBC would be getting ARM support. JDBC is an area where most of the code that you write tends to focus more on exception handling and resource management than the actual business logic, so ARM can be put to good use here.

Lets say you have to retrieve and print out some employee salaries from a mySQL database. To refresh your memory, here’s an example of the current way of establishing a connection to a MySQL database using ye olde Connection, Statement and ResultSet interfaces:

String connectionURL = 'jdbc:mysql://localhost:3306/myDB';
Connection connection = null;
Statement st = null;
ResultSet rs = null;
try
{
    Class.forName('com.mysql.jdbc.Driver').newInstance();
    connection = DriverManager.getConnection(connectionURL, 'root', 'admin');
    st = connection.createStatement();
    rs = st.executeQuery('Select * from EMPLOYEE_SALARIES');
    while (rs.next())
    {
        System.out.println('EMPLOYEE_NAME/EMPLOYEE_SALARY');
        System.out.println(rs.getString(1) + '/' + rs.getString(2));
    }
}
catch (ClassNotFoundException ex)
{
    ex.printStackTrace();
}
catch (SQLException ex)
{
    ex.printStackTrace();
}
catch (InstantiationException ex)
{
    ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
    ex.printStackTrace();
}
finally
{
    try
    {
        if (rs != null && !rs.isClosed())
        {
            rs.close();
        }
        if (st != null && !st.isClosed())
        {
            st.close();
        }
        if (connection != null && !connection.isClosed())
        {
            connection.close();
        }
    }
    catch (SQLException ex)
    {
        ex.printStackTrace();
    }
}

What is wrong with the above code? Compiler-wise…. nothing. But the abundance of exception-handling code simply overwhelms the core executeQuery()/parsing of the result set business logic.

If we look back to the ARM version of the first example, applying that paradigm to the JDBC code example above, should result in a cleaner version. More specifically there will be no  ’catch’ clauses and no code to close the opened connections, statements and result sets. An approximate version might look something like the following:

String connectionURL = 'jdbc:mysql://localhost:3306/myDB';
try
(
    Connection connection =
        DriverManager.getConnection(connectionURL, 'root', 'admin');
    Statement st = connection.createStatement();
    ResultSet rs = st.executeQuery('Select * from EMPLOYEE_SALARIES');
)
{
    Class.forName('com.mysql.jdbc.Driver').newInstance();
    while (rs.next())
    {
        System.out.println('EMPLOYEE_NAME/EMPLOYEE_SALARY');
        System.out.println(rs.getString(1) + '/' + rs.getString(2));
    }
}

The differences between ‘without ARM’ and ‘with ARM’ cases is indeed considerable. With ARM, the developer’s focus remains on the business logic.

Nevertheless, using ARM for automatically closing previously-opened resources raises some concerns. The most obvious of these is how the closing of the Connection will affect transactional behaviour. Should all transactions be committed or rolled back before ARM calls “close()” on the Connection? If the runtime resource manager decides to close the connection suddenly and not all changes have been committed, what would be the consequences of automatically rolling back everything? These questions are more will be answered in a follow up post once we get our hands on the first ARM/JDBC supported build.

Cheers,
Martijn, Ben and Dragos (our fantastic intern!).

Did you like this? Share it: