[concurrency-interest] syntax sugar for lazy instantiation

Ashley Williams ashpublic at mac.com
Tue Jun 23 19:02:44 EDT 2009


I guess what's making it hard for me to comment on this is that I  
don't have the source code for FutureTask so I have no idea
what it is doing under the hood (thanks Apple). I agree it would be  
nice not to have to introduce a new class and if the
"happy path" is just a null check as with DCL then I would definitely  
see the benefit of this approach.

The only thing that makes me a little uncomfortable is that I guess  
FutureTask must contain more than one field to record
the exception, callable and result for example. Therefore I would be  
effectively swapping a single field with multiple.
I'm not saying this is a deal breaker though.

On 23 Jun 2009, at 23:32, Ben Manes wrote:

> While I understand the performance concern, I have not seen a  
> problem in practice and the locking in FutureTask is well  
> optimized.  It provides a nice idiom than sprinkling the code with  
> double-checked locking tricks or introducing a new interface.  By  
> using a future you leverage an existing interface and can utilize it  
> to chain lower-level futures for performing post-processing logic on  
> the client.  For example...
>
>    // written ad-hoc...
>    // Retrieves the entry in a remote caching layer where the key/ 
> value are use a custom serialization scheme
>    // The client's future is bubbled up and performs post-processing  
> to deserialize the value into object form
>    // The "lazyFuture" provides the idiom to run the callable, which  
> blocks on the inner future, on a Future#get().
>     public <V> Future<V> get(K key) {
>         String externalKey = serializer(key);
>         final Future<String> future = remoteCache.get(externalKey);
>         return Futures.lazyFuture(new Callable<V>() {
>              public V call() throws Exception {
>                  return deserializer(future.get());
>              }
>          });
>     }
>
> Because this idiom is generalized into a custom utility,  
> Futures#lazyFuture(), the implementation can tuned globally if there  
> is a performance problem.  Since I haven't experienced any  
> noticeable overhead, the simplest approach for me was to rely on  
> FutureTask until that problem occurs.  If a problem later occurs  
> during performance testing, then implementing a Future with double- 
> checked locking is simple, easy to test, and applies globally to all  
> of my usages.
>
> From: Ashley Williams <ashpublic at mac.com>
> To: Ben Manes <ben_manes at yahoo.com>
> Cc: concurrency-interest at cs.oswego.edu
> Sent: Tuesday, June 23, 2009 11:38:44 AM
> Subject: Re: [concurrency-interest] syntax sugar for lazy  
> instantiation
>
> I'm going to have to think about this one since I've used futures  
> but never connected them to double checked locks.
> Fo instance I want to check that:
>
> - I get fast access to field  99% of the time
> - I only pay for lock when initializing a field.
>
> I'm sure there are a ton of tricks like this, what would be great is  
> an "effective threading" book for those that have
> read the theory and want to get straight to idioms.
>
> On 23 Jun 2009, at 19:19, Ben Manes wrote:
>
>> I use this trick all the time, but its already supplied via  
>> FutureTask.  It has very similar semantics to your code.  This  
>> trick can be extended to build lazy maps (and other lazy  
>> structures) which is also very convenient.
>>
>> public class Example {
>>     private final FutureTask<Computation> future = new  
>> FutureTask<Computation>(new Computable());
>>
>>     // Lazily computes the work and returns the value
>>     public Computation getComputation() throws Exception {
>>         future.run(); // no-ops on all subsequent calls
>>         return future.get();
>>     }
>>
>>     private static final class Computable implements  
>> Callable<Computation> {
>>         public Computation call() {
>>           // do work, return
>>         }
>>     }
>> }
>>
>> From: Ashley Williams <ashpublic at mac.com>
>> To: concurrency-interest at cs.oswego.edu
>> Sent: Tuesday, June 23, 2009 10:05:24 AM
>> Subject: [concurrency-interest] syntax sugar for lazy instantiation
>>
>> It seems to me that the only reason to use an intrinsic lock on a  
>> lazy getter (stick a synchronized keyword
>> on the method signature) is convenience of syntax. Please correct  
>> me if I am wrong.
>>
>> So is one idea to simplify lazy instantiation, feedback welcome if  
>> anybody can improve on it. It's based
>> on the observation that double checked locking is mostly  
>> boilerplate except for the line that creates
>> the instance and so I've factored it out into a callable interface.
>>
>> Admittedly the anonymous class makes for a more verbose  
>> constructor, but at least the dcl logic is
>> now encapsulated. And if java had support for closures then the  
>> readability problem would go away.
>>
>> So first the class:
>>
>> @ThreadSafe
>> public final class LazyField<T> {
>> 	private volatile T obj;
>> 	private final Callable<T> callable;
>>
>> 	public LazyField(Callable<T> callable) {
>> 		this.callable = callable;
>> 	}
>>
>> 	public T get() {
>> 		if (obj == null) {
>> 			synchronized (this) {
>> 				if (obj == null) {
>> 					obj = callable.call();
>> 				}
>> 			}
>> 		}
>> 		return obj;
>> 	}
>> }
>>
>> and here is an example usage:
>>
>> @ThreadSafe
>> public final class MyClass {
>> 	private final LazyField<String> message;
>>
>> 	public MyClass() {
>> 		this.message = new LazyField<String>(new Callable<String>() {
>> 			public String call() throws Exception {
>> 				return "hello world";
>> 			}
>> 		});
>> 	}
>>
>> 	public String getMessage() {
>> 		return message.get();
>> 	}
>> }
>>
>> - Ashley Williams
>>
>>
>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20090624/dc220427/attachment-0001.html>


More information about the Concurrency-interest mailing list