[concurrency-interest] syntax sugar for lazy instantiation

Ashley Williams ashpublic at mac.com
Wed Jun 24 05:33:07 EDT 2009


Actually there isn't a version of Java6 on the 32 bit mac, which is  
what I have, but I've now got the java5 docs - this is a great help,  
thanks.

I took a look at your LazyReference class and it looks similar to the  
one suggested by Ben. My requirements for lazy behavior are typically
because a resource I need isn't available at construction time and not  
because the result takes a long time to calculate. Given that, would
you still recommend using future task?

I'm starting to see how ingrained my tendency is to favor space,  
although this is more because mutable objects are second nature to me
rather than a deliberate attempt to optimize.


On 24 Jun 2009, at 03:37, Jed Wesley-Smith wrote:

> The Java6 source code can be downloaded as the "Developer  
> Documentation" from http://developer.apple.com/java/download/
>
> We have a LazyReference[1] class used extensively internally that  
> encapsulates all the required functionality. It is based on  
> FutureTask as well, and is fully optimised[2] for performance.
>
> I am very wary when people try to optimise for space over  
> correctness and even readability. Concurrency is so hard for most  
> developers that favouring correctness over space (unless space is  
> proven to be the first order issue) seems like premature optimisation.
>
> cheers,
> jed.
>
> [1] LazyReference from the atlassian-util-concurrent library
> source: http://labs.atlassian.com/source/browse/CONCURRENT/trunk/src/main/java/com/atlassian/util/concurrent/LazyReference.java?r=2605
> doc: http://labs.atlassian.com/wiki/display/CONCURRENT/LazyReference
> [2] FutureTask.run() is a no-op if already run, but this is  
> implemented by a CAS update on the state which can perform worse  
> than a simple read of the state (isDone()) under certain  
> circumstances.
>
> Ashley Williams wrote:
>> 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  
>>> <mailto:ashpublic at mac.com>>
>>> *To:* Ben Manes <ben_manes at yahoo.com <mailto:ben_manes at yahoo.com>>
>>> *Cc:* concurrency-interest at cs.oswego.edu <mailto: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 <mailto:ashpublic at mac.com 
>>>> >>
>>>> *To:* concurrency-interest at cs.oswego.edu <mailto: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
>>>>
>>>>
>>>
>>>
>>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>



More information about the Concurrency-interest mailing list