Java tutorial
/* * 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(); } } }