Mega Code Archive

 
Categories / Java / Collections Data Structure
 

Lazy Loading Reference

/*  * Copyright 2008-2010 the T2 Project ant the Others.  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ //package org.t2framework.commons.util; import java.lang.ref.WeakReference; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicReference; public class LazyLoadingReference<T> {   protected Factory<T> factory;   protected AtomicReference<WeakReference<Future<T>>> reference = new AtomicReference<WeakReference<Future<T>>>();   public LazyLoadingReference(Factory<T> factory) {     this.factory = factory;   }   public T get() throws IllegalStateException {     while (true) {       WeakReference<Future<T>> ref = reference.get();       boolean valid = true;       if (ref == null) {         FutureTask<T> f = new FutureTask<T>(new Callable<T>() {           @Override           public T call() throws Exception {             return factory.create();           }         });         ref = new WeakReference<Future<T>>(f);         if (valid = reference.compareAndSet(null, ref)) {           f.run();         }       }       if (valid) {         try {           Future<T> f = ref.get();           if (f != null) {             return f.get();           } else {             reference.compareAndSet(ref, null);           }         } catch (CancellationException e) {           reference.compareAndSet(ref, null);         } catch (ExecutionException e) {           throw new IllegalStateException(e.getCause());         } catch (Exception e) {           throw new IllegalStateException(e);         }       }     }   }   public interface Factory<T> {     T create() throws CancellationException, Exception;   } } ------------------------- /*  * Copyright 2008-2009 the T2 Project ant the Others.  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package org.t2framework.commons.util; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.CancellationException; import org.t2framework.commons.cache.Cache; import org.t2framework.commons.cache.CacheFactory; import org.t2framework.commons.cache.CacheType; import junit.framework.TestCase; public class LazyLoadingReferenceTest extends TestCase {   public void test_loadSimple() throws Exception {     LazyLoadingReference<String> target = new LazyLoadingReference<String>(         new LazyLoadingReference.Factory<String>() {           public String create() {             return "hoge";           }         });     assertEquals("hoge", target.get());   }   public void test_loadSimple2() throws Exception {     LazyLoadingReference<Cache<String, String>> t2 = new LazyLoadingReference<Cache<String, String>>(         new LazyLoadingReference.Factory<Cache<String, String>>() {           @Override           public Cache<String, String> create()               throws CancellationException {             Cache<String, String> c = CacheFactory                 .createCache(CacheType.DEFAULT);             c.put("aaa", "bbb");             return c;           }         });     Cache<String, String> cache = t2.get();     assertNotNull(cache);     assertNotNull(cache.get("aaa"));   }   public void test_exception() throws Exception {     final Exception e = new Exception();     LazyLoadingReference<String> target = new LazyLoadingReference<String>(         new LazyLoadingReference.Factory<String>() {           public String create() throws Exception {             throw e;           }         });     try {       target.get();       fail();     } catch (IllegalStateException t) {       assertNotNull(t.getCause());       assertTrue(t.getCause().getClass() == Exception.class);       assertEquals(e, t.getCause());     }   }   public void test_loadHeavy() throws Exception {     final LazyLoadingReference<String> target = new LazyLoadingReference<String>(         new LazyLoadingReference.Factory<String>() {           public String create() {             return "hoge";           }         });     final Random random = new Random(System.currentTimeMillis());     List<Thread> list = new ArrayList<Thread>();     for (int i = 0; i < 20; i++) {       Runnable r = new Runnable() {         public void run() {           try {             long l = random.nextLong() % 100;             Thread.sleep(l < 0 ? l * -1 : l);             assertEquals("hoge", target.get());           } catch (InterruptedException e) {             e.printStackTrace();           }         }       };       Thread t = new Thread(r);       list.add(t);       t.start();     }     for (Thread t : list) {       t.join();     }   } }