commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r929189 - in /commons/proper/lang/trunk/src: main/java/org/apache/commons/lang3/concurrent/ test/java/org/apache/commons/lang3/concurrent/
Date Tue, 30 Mar 2010 16:49:23 GMT
Author: oheger
Date: Tue Mar 30 16:49:22 2010
New Revision: 929189

URL: http://svn.apache.org/viewvc?rev=929189&view=rev
Log:
LANG-609: Added AtomicInitializer class. Introduced new ConcurrentInitializer interface which
is now implemented by all all initializer classes.

Added:
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
  (with props)
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
  (with props)
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
  (with props)
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
  (with props)
Modified:
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/BackgroundInitializer.java
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/LazyInitializer.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/ConcurrentUtilsTest.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java

Added: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java?rev=929189&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
(added)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
Tue Mar 30 16:49:22 2010
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang3.concurrent;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * <p>
+ * A specialized implementation of the {@code ConcurrentInitializer} interface
+ * based on an {@link AtomicReference} variable.
+ * </p>
+ * <p>
+ * This class maintains a member field of type {@code AtomicReference}. It
+ * implements the following algorithm to create and initialize an object in its
+ * {@link #get()} method:
+ * <ul>
+ * <li>First it is checked whether the {@code AtomicReference} variable contains
+ * already a value. If this is the case, the value is directly returned.</li>
+ * <li>Otherwise the {@link #initialize()} method is called. This method must be
+ * defined in concrete subclasses to actually create the managed object.</li>
+ * <li>After the object was created by {@link #initialize()} it is checked
+ * whether the {@code AtomicReference} variable is still undefined. This has to
+ * be done because in the meantime another thread may have initialized the
+ * object. If the reference is still empty, the newly created object is stored
+ * in it and returned by this method.</li>
+ * <li>Otherwise the value stored in the {@code AtomicReference} is returned.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Because atomic variables are used this class does not need any
+ * synchronization. So there is no danger of deadlock, and access to the managed
+ * object is efficient. However, if multiple threads access the {@code
+ * AtomicInitializer} object before it has been initialized almost at the same
+ * time, it can happen that {@link #initialize()} is called multiple times. The
+ * algorithm outlined above guarantees that {@link #get()} always returns the
+ * same object though.
+ * </p>
+ * <p>
+ * Compared with the {@link LazyInitializer} class, this class can be more
+ * efficient because it does not need synchronization. The drawback is that the
+ * {@link #initialize()} method can be called multiple times which may be
+ * problematic if the creation of the managed object is expensive. As a rule of
+ * thumb this initializer implementation is preferable if there are not too many
+ * threads involved and the probability that multiple threads access an
+ * uninitialized object is small. If there is high parallelism,
+ * {@link LazyInitializer} is more appropriate.
+ * </p>
+ *
+ * @author Apache Software Foundation
+ * @version $Id$
+ * @param <T> the type of the object managed by this initializer class
+ */
+public abstract class AtomicInitializer<T> implements ConcurrentInitializer<T>
{
+    /** Holds the reference to the managed object. */
+    private final AtomicReference<T> reference = new AtomicReference<T>();
+
+    /**
+     * Returns the object managed by this initializer. The object is created if
+     * it is not available yet and stored internally. This method always returns
+     * the same object.
+     *
+     * @return the object created by this {@code AtomicInitializer}
+     * @throws ConcurrentException if an error occurred during initialization of
+     * the object
+     */
+    public T get() throws ConcurrentException {
+        T result = reference.get();
+
+        if (result == null) {
+            result = initialize();
+            if (!reference.compareAndSet(null, result)) {
+                // another thread has initialized the reference
+                result = reference.get();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates and initializes the object managed by this {@code
+     * AtomicInitializer}. This method is called by {@link #get()} when the
+     * managed object is not available yet. An implementation can focus on the
+     * creation of the object. No synchronization is needed, as this is already
+     * handled by {@code get()}. As stated by the class comment, it is possible
+     * that this method is called multiple times.
+     *
+     * @return the managed data object
+     * @throws ConcurrentException if an error occurs during object creation
+     */
+    protected abstract T initialize() throws ConcurrentException;
+}

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/AtomicInitializer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/BackgroundInitializer.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/BackgroundInitializer.java?rev=929189&r1=929188&r2=929189&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/BackgroundInitializer.java
(original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/BackgroundInitializer.java
Tue Mar 30 16:49:22 2010
@@ -82,7 +82,8 @@ import java.util.concurrent.Future;
  * @version $Id$
  * @param <T> the type of the object managed by this initializer class
  */
-public abstract class BackgroundInitializer<T> {
+public abstract class BackgroundInitializer<T> implements
+        ConcurrentInitializer<T> {
     /** The external executor service for executing tasks. */
     private ExecutorService externalExecutor;
 

Added: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java?rev=929189&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
(added)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
Tue Mar 30 16:49:22 2010
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang3.concurrent;
+
+/**
+ * <p>
+ * Definition of an interface for the thread-safe initialization of objects.
+ * </p>
+ * <p>
+ * The idea behind this interface is to provide access to an object in a
+ * thread-safe manner. A {@code ConcurrentInitializer} can be passed to multiple
+ * threads which can all access the object produced by the initializer. Through
+ * the {@link #getInitializedObject()} method the object can be queried.
+ * </p>
+ * <p>
+ * Concrete implementations of this interface will use different strategies for
+ * the creation of the managed object, e.g. lazy initialization or
+ * initialization in a background thread. This is completely transparent to
+ * client code, so it is possible to change the initialization strategy without
+ * affecting clients.
+ * </p>
+ *
+ * @author Apache Software Foundation
+ * @version $Id$
+ * @param <T> the type of the object managed by this initializer class
+ */
+public interface ConcurrentInitializer<T> {
+    /**
+     * Returns the fully initialized object produced by this {@code
+     * ConcurrentInitializer}. A concrete implementation here returns the
+     * results of the initialization process. This method may block until
+     * results are available. Typically, once created the result object is
+     * always the same.
+     *
+     * @return the object created by this {@code ConcurrentException}
+     * @throws ConcurrentException if an error occurred during initialization of
+     * the object
+     */
+    T get() throws ConcurrentException;
+}

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java?rev=929189&r1=929188&r2=929189&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
(original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java
Tue Mar 30 16:49:22 2010
@@ -166,6 +166,46 @@ public class ConcurrentUtils {
 
     //-----------------------------------------------------------------------
     /**
+     * Invokes the specified {@code ConcurrentInitializer} and returns the
+     * object produced by the initializer. This method just invokes the {@code
+     * get()} method of the given {@code ConcurrentInitializer}. It is
+     * <b>null</b>-safe: if the argument is <b>null</b>, result is
also
+     * <b>null</b>.
+     *
+     * @param <T> the type of the object produced by the initializer
+     * @param initializer the {@code ConcurrentInitializer} to be invoked
+     * @return the object managed by the {@code ConcurrentInitializer}
+     * @throws ConcurrentException if the {@code ConcurrentInitializer} throws
+     * an exception
+     */
+    public static <T> T initialize(ConcurrentInitializer<T> initializer)
+            throws ConcurrentException {
+        return (initializer != null) ? initializer.get() : null;
+    }
+
+    /**
+     * Invokes the specified {@code ConcurrentInitializer} and transforms
+     * occurring exceptions to runtime exceptions. This method works like
+     * {@link #initialize(ConcurrentInitializer)}, but if the {@code
+     * ConcurrentInitializer} throws a {@link ConcurrentException}, it is
+     * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}.
+     * So client code does not have to deal with checked exceptions.
+     *
+     * @param <T> the type of the object produced by the initializer
+     * @param initializer the {@code ConcurrentInitializer} to be invoked
+     * @return the object managed by the {@code ConcurrentInitializer}
+     * @throws ConcurrentRuntimeException if the initializer throws an exception
+     */
+    public static <T> T initializeUnchecked(ConcurrentInitializer<T> initializer)
{
+        try {
+            return initialize(initializer);
+        } catch (ConcurrentException cex) {
+            throw new ConcurrentRuntimeException(cex.getCause());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
      * <p>
      * Gets an implementation of <code>Future</code> that is immediately done
      * and returns the specified constant value.

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/LazyInitializer.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/LazyInitializer.java?rev=929189&r1=929188&r2=929189&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/LazyInitializer.java
(original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/concurrent/LazyInitializer.java
Tue Mar 30 16:49:22 2010
@@ -76,7 +76,7 @@ package org.apache.commons.lang3.concurr
  * @version $Id$
  * @param <T> the type of the object managed by this initializer class
  */
-public abstract class LazyInitializer<T> {
+public abstract class LazyInitializer<T> implements ConcurrentInitializer<T>
{
     /** Stores the managed object. */
     private volatile T object;
 
@@ -85,8 +85,10 @@ public abstract class LazyInitializer<T>
      * is created. After that it is cached and can be accessed pretty fast.
      *
      * @return the object initialized by this {@code LazyInitializer}
+     * @throws ConcurrentException if an error occurred during initialization of
+     * the object
      */
-    public T get() {
+    public T get() throws ConcurrentException {
         // use a temporary variable to reduce the number of reads of the
         // volatile field
         T result = object;
@@ -111,6 +113,7 @@ public abstract class LazyInitializer<T>
      * handled by {@code get()}.
      *
      * @return the managed data object
+     * @throws ConcurrentException if an error occurs during object creation
      */
-    protected abstract T initialize();
+    protected abstract T initialize() throws ConcurrentException;
 }

Added: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java?rev=929189&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
(added)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
Tue Mar 30 16:49:22 2010
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang3.concurrent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.Test;
+
+/**
+ * <p>
+ * An abstract base class for tests of concrete {@code ConcurrentInitializer}
+ * implementations.
+ * </p>
+ * <p>
+ * This class provides some basic tests for initializer implementations. Derived
+ * class have to create a {@link ConcurrentInitializer} object on which the
+ * tests are executed.
+ * </p>
+ *
+ * @author Apache Software Foundation
+ * @version $Id$
+ */
+public abstract class AbstractConcurrentInitializerTest {
+    /**
+     * Tests a simple invocation of the get() method.
+     */
+    @Test
+    public void testGet() throws ConcurrentException {
+        assertNotNull("No managed object", createInitializer().get());
+    }
+
+    /**
+     * Tests whether sequential get() invocations always return the same
+     * instance.
+     */
+    @Test
+    public void testGetMultipleTimes() throws ConcurrentException {
+        ConcurrentInitializer<Object> initializer = createInitializer();
+        Object obj = initializer.get();
+        for (int i = 0; i < 10; i++) {
+            assertEquals("Got different object at " + i, obj, initializer.get());
+        }
+    }
+
+    /**
+     * Tests whether get() can be invoked from multiple threads concurrently.
+     * Always the same object should be returned.
+     */
+    @Test
+    public void testGetConcurrent() throws ConcurrentException,
+            InterruptedException {
+        final ConcurrentInitializer<Object> initializer = createInitializer();
+        final int threadCount = 20;
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        class GetThread extends Thread {
+            Object object;
+
+            @Override
+            public void run() {
+                try {
+                    // wait until all threads are ready for maximum parallelism
+                    startLatch.await();
+                    // access the initializer
+                    object = initializer.get();
+                } catch (InterruptedException iex) {
+                    // ignore
+                } catch (ConcurrentException cex) {
+                    object = cex;
+                }
+            }
+        }
+
+        GetThread[] threads = new GetThread[threadCount];
+        for (int i = 0; i < threadCount; i++) {
+            threads[i] = new GetThread();
+            threads[i].start();
+        }
+
+        // fire all threads and wait until they are ready
+        startLatch.countDown();
+        for (Thread t : threads) {
+            t.join();
+        }
+
+        // check results
+        Object managedObject = initializer.get();
+        for (GetThread t : threads) {
+            assertEquals("Wrong object", managedObject, t.object);
+        }
+    }
+
+    /**
+     * Creates the {@link ConcurrentInitializer} object to be tested. This
+     * method is called whenever the test fixture needs to be obtained.
+     *
+     * @return the initializer object to be tested
+     */
+    protected abstract ConcurrentInitializer<Object> createInitializer();
+}

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AbstractConcurrentInitializerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java?rev=929189&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
(added)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
Tue Mar 30 16:49:22 2010
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang3.concurrent;
+
+/**
+ * Test class for {@code AtomicInitializer}.
+ *
+ * @author Apache Software Foundation
+ * @version $Id$
+ */
+public class AtomicInitializerTest extends AbstractConcurrentInitializerTest {
+    /**
+     * Returns the initializer to be tested.
+     *
+     * @return the {@code AtomicInitializer}
+     */
+    @Override
+    protected ConcurrentInitializer<Object> createInitializer() {
+        return new AtomicInitializer<Object>() {
+            @Override
+            protected Object initialize() throws ConcurrentException {
+                return new Object();
+            }
+        };
+    }
+}

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/AtomicInitializerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/ConcurrentUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/ConcurrentUtilsTest.java?rev=929189&r1=929188&r2=929189&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/ConcurrentUtilsTest.java
(original)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/ConcurrentUtilsTest.java
Tue Mar 30 16:49:22 2010
@@ -25,6 +25,7 @@ import java.util.concurrent.ExecutionExc
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
+import org.easymock.EasyMock;
 import org.junit.Test;
 
 /**
@@ -303,6 +304,75 @@ public class ConcurrentUtilsTest {
 
     //-----------------------------------------------------------------------
     /**
+     * Tests initialize() for a null argument.
+     */
+    @Test
+    public void testInitializeNull() throws ConcurrentException {
+        assertNull("Got a result", ConcurrentUtils.initialize(null));
+    }
+
+    /**
+     * Tests a successful initialize() operation.
+     */
+    @Test
+    public void testInitialize() throws ConcurrentException {
+        @SuppressWarnings("unchecked")
+        ConcurrentInitializer<Object> init = EasyMock
+                .createMock(ConcurrentInitializer.class);
+        final Object result = new Object();
+        EasyMock.expect(init.get()).andReturn(result);
+        EasyMock.replay(init);
+        assertSame("Wrong result object", result, ConcurrentUtils
+                .initialize(init));
+        EasyMock.verify(init);
+    }
+
+    /**
+     * Tests initializeUnchecked() for a null argument.
+     */
+    @Test
+    public void testInitializeUncheckedNull() {
+        assertNull("Got a result", ConcurrentUtils.initializeUnchecked(null));
+    }
+
+    /**
+     * Tests a successful initializeUnchecked() operation.
+     */
+    @Test
+    public void testInitializeUnchecked() throws ConcurrentException {
+        @SuppressWarnings("unchecked")
+        ConcurrentInitializer<Object> init = EasyMock
+                .createMock(ConcurrentInitializer.class);
+        final Object result = new Object();
+        EasyMock.expect(init.get()).andReturn(result);
+        EasyMock.replay(init);
+        assertSame("Wrong result object", result, ConcurrentUtils
+                .initializeUnchecked(init));
+        EasyMock.verify(init);
+    }
+
+    /**
+     * Tests whether exceptions are correctly handled by initializeUnchecked().
+     */
+    @Test
+    public void testInitializeUncheckedEx() throws ConcurrentException {
+        @SuppressWarnings("unchecked")
+        ConcurrentInitializer<Object> init = EasyMock
+                .createMock(ConcurrentInitializer.class);
+        final Exception cause = new Exception();
+        EasyMock.expect(init.get()).andThrow(new ConcurrentException(cause));
+        EasyMock.replay(init);
+        try {
+            ConcurrentUtils.initializeUnchecked(init);
+            fail("Exception not thrown!");
+        } catch (ConcurrentRuntimeException crex) {
+            assertSame("Wrong cause", cause, crex.getCause());
+        }
+        EasyMock.verify(init);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
      * Tests constant future.
      */
     @Test

Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java?rev=929189&r1=929188&r2=929189&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
(original)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/concurrent/LazyInitializerTest.java
Tue Mar 30 16:49:22 2010
@@ -16,82 +16,31 @@
  */
 package org.apache.commons.lang3.concurrent;
 
-import java.util.concurrent.CountDownLatch;
-
-import junit.framework.TestCase;
+import org.junit.Before;
 
 /**
  * Test class for {@code LazyInitializer}.
  *
  * @version $Id$
  */
-public class LazyInitializerTest extends TestCase {
+public class LazyInitializerTest extends AbstractConcurrentInitializerTest {
     /** The initializer to be tested. */
     private LazyInitializerTestImpl initializer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         initializer = new LazyInitializerTestImpl();
     }
 
     /**
-     * Tests obtaining the managed object.
-     */
-    public void testGet() {
-        assertNotNull("No managed object", initializer.get());
-    }
-
-    /**
-     * Tests whether sequential get() invocations always return the same
-     * instance.
-     */
-    public void testGetMultipleTimes() {
-        Object obj = initializer.get();
-        for (int i = 0; i < 10; i++) {
-            assertEquals("Got different object at " + i, obj, initializer.get());
-        }
-    }
-
-    /**
-     * Tests invoking get() from multiple threads concurrently.
+     * Returns the initializer to be tested. This implementation returns the
+     * {@code LazyInitializer} created in the {@code setUp()} method.
+     *
+     * @return the initializer to be tested
      */
-    public void testGetConcurrent() throws InterruptedException {
-        final int threadCount = 20;
-        final CountDownLatch startLatch = new CountDownLatch(1);
-        class GetThread extends Thread {
-            Object object;
-
-            @Override
-            public void run() {
-                try {
-                    // wait until all threads are ready for maximum parallelism
-                    startLatch.await();
-                    // access the initializer
-                    object = initializer.get();
-                } catch (InterruptedException iex) {
-                    // ignore
-                }
-            }
-        }
-
-        GetThread[] threads = new GetThread[threadCount];
-        for (int i = 0; i < threadCount; i++) {
-            threads[i] = new GetThread();
-            threads[i].start();
-        }
-
-        // fire all threads and wait until they are ready
-        startLatch.countDown();
-        for (Thread t : threads) {
-            t.join();
-        }
-
-        // check results
-        Object managedObject = initializer.get();
-        for (GetThread t : threads) {
-            assertEquals("Wrong object", managedObject, t.object);
-        }
+    @Override
+    protected ConcurrentInitializer<Object> createInitializer() {
+        return initializer;
     }
 
     /**



Mime
View raw message