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;
}
/**