Proposal: Automatic Resource Management

Peter Mount peter at retep.org.uk
Sat Mar 7 03:11:54 PST 2009


On Sat, Mar 7, 2009 at 10:02 AM, Xavi Miró <xmirog at gmail.com> wrote:

> Neal,
>
>   this proposal tries to achieve big benefits with small changes. In my
> opinion, Streams, Readers, Writers, Formatters, Channels, Sockets,
> Connections, Statements, ResultSets, or java.awt.Graphics are much more
> used than Locks. This does not mean that Locks are not important. If the
> proposal can be applied to the formers it will be a huge benefit,
> although Locks can't be used directly with it.
>
>   I agree with Bob, adapters can be used for many use cases where
> "close" methods are incompatible with the Disposable or Resource
> interface. And although the proposal is not designed to manage Locks,
> perhaps a kind of "safe unlocker" can be easily made, so this original
> code:
>
>     myLock.lock();
>     try {
>         // access the resource protected by myLock
>     } finally {
>         myLock.unlock();
>     }
>
> could be written this way:
>
>     try (SafeUnlocker = new SafeUnlocker(myLock)) {
>         // access the resource protected by myLock
>     }
>
> where SafeUnlocker would be more or less like this:
>
> public class SafeUnlocker implements Disposable {
>
>  private final Lock lock;
>
>  public SafeUnlocker(Lock lock){
>    this.lock = lock;
>    lock.lock();
>  }
>
>  public void close throws Exception {
>    lock.unlock();
>  }
> }
>
> The name SafeUnlocker maybe it's not appropriate, but I haven't found a
> better one. There can be problems in this source code that I haven't
> seen...this is only an idea.
>
>  Regards,
>
>      Xavi
>
>
I use the concurrency package extensively, mainly within a high load online
gaming environment and I would be concerned about the overhead of the large
number of SafeUnlocker instances generated, their effects with the Garbage
Collector and the increase in the memory footprint when the locks are used
recursively (ReentrantLock and ReadWriteReentrantLock) - please correct me
if I'm wrong here.

The only way I can see my concerns satisfied would be to use something like:

public class DisposableLock implements Disposable {

 private final Lock lock;

 public DisposableLock(Lock lock){
   this.lock = lock;
   lock.lock();
 }

 public void close throws Exception {
   lock.unlock();
 }
}

Then in my useage:

final DisposableLock lock = new DisposableLock( new ReentrantLock() );

public void method()
{
   try ( lock ) {
        // access the resource protected by lock
    }
}

That would account for a simple ReentrantLock, but for
ReentrantReadWriteLock we could then use something like:

final ReadWriteLock lock = new ReentrantReadWriteLock();
final DisposableLock readLock = new DisposableLock( lock.readLock() );
final DisposableLock writeLock = new DisposableLock( lock.writeLock() );

public void method()
{
   try ( readLock ) {
        // access the resource protected by the read lock
    }
}

public void setSomething()
{
   try ( writeLock ) {
        // access the resource protected by the write lock
    }
}

It does make the code a lot easier to read, and is cleaner than how I
currently do something similar in 1.6 - naughtily using an annotation
processor to inject a try {} finally {} around the locked methods.

Peter

-- 
Peter Mount
e: peter at retep.org.uk
w: http://retep.org
Jabber/GTalk: peter at retep.org MSN: retep207 at hotmail.com



More information about the coin-dev mailing list