From: <tho...@us...> - 2011-02-17 13:38:54
|
Revision: 4206 http://bigdata.svn.sourceforge.net/bigdata/?rev=4206&view=rev Author: thompsonbry Date: 2011-02-17 13:38:48 +0000 (Thu, 17 Feb 2011) Log Message: ----------- Added constructor variants for LinkedBlockingDeque which permit the caller to pass in their ReentrantLock. The intention is to support design patterns where an outer lock is used to guard operations both outside of the collection and within the collection. When the collection uses its own lock, this can create a deadlock if the outer class issues concurrent requests which lead to blocking operation on the collection. Modified Paths: -------------- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166/LinkedBlockingDeque.java branches/QUADS_QUERY_BRANCH/bigdata/src/test/com/bigdata/jsr166/LinkedBlockingDequeTest.java Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166/LinkedBlockingDeque.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166/LinkedBlockingDeque.java 2011-02-17 12:56:14 UTC (rev 4205) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166/LinkedBlockingDeque.java 2011-02-17 13:38:48 UTC (rev 4206) @@ -125,13 +125,13 @@ private final int capacity; /** Main lock guarding all access */ - final ReentrantLock lock = new ReentrantLock(); + final ReentrantLock lock;// = new ReentrantLock(); /** Condition for waiting takes */ - private final Condition notEmpty = lock.newCondition(); + private final Condition notEmpty;// = lock.newCondition(); /** Condition for waiting puts */ - private final Condition notFull = lock.newCondition(); + private final Condition notFull;// = lock.newCondition(); /** * Creates a {@code LinkedBlockingDeque} with a capacity of @@ -142,14 +142,52 @@ } /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE} using the caller's lock. + */ + public LinkedBlockingDeque(final ReentrantLock lock) { + this(Integer.MAX_VALUE, lock); + } + + /** * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity. * * @param capacity the capacity of this deque * @throws IllegalArgumentException if {@code capacity} is less than 1 */ public LinkedBlockingDeque(int capacity) { + this(capacity, new ReentrantLock()); +// if (capacity <= 0) throw new IllegalArgumentException(); +// this.capacity = capacity; + } + + /** + * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity and + * the caller's {@link ReentrantLock} object. + * <p> + * <strong>Caution:</strong> By using the caller's lock, this constructor + * allows the caller to break the encapsulation of the synchronization and + * lock-based notification (signals). This can be used advantageously to + * create designs where an outer lock is shared by the collection which + * avoid deadlock arising from blocking operations on an inner lock while + * holding a distinct outer lock. However, the caller's decisions about its + * lock are no longer independent of the design decisions within this class + * since they share the same lock. + * + * @param capacity + * the capacity of this deque + * @param lock + * the lock object. + * @throws IllegalArgumentException + * if {@code capacity} is less than 1 + */ + public LinkedBlockingDeque(final int capacity, final ReentrantLock lock) { if (capacity <= 0) throw new IllegalArgumentException(); + if (lock == null) throw new NullPointerException(); this.capacity = capacity; + this.lock = lock; + this.notEmpty = lock.newCondition(); + this.notFull = lock.newCondition(); } /** Modified: branches/QUADS_QUERY_BRANCH/bigdata/src/test/com/bigdata/jsr166/LinkedBlockingDequeTest.java =================================================================== --- branches/QUADS_QUERY_BRANCH/bigdata/src/test/com/bigdata/jsr166/LinkedBlockingDequeTest.java 2011-02-17 12:56:14 UTC (rev 4205) +++ branches/QUADS_QUERY_BRANCH/bigdata/src/test/com/bigdata/jsr166/LinkedBlockingDequeTest.java 2011-02-17 13:38:48 UTC (rev 4206) @@ -7,6 +7,8 @@ import junit.framework.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.locks.ReentrantLock; + import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.io.*; @@ -326,7 +328,7 @@ */ public void testConstructor3() { try { - LinkedBlockingDeque q = new LinkedBlockingDeque(null); + LinkedBlockingDeque q = new LinkedBlockingDeque((Collection)null); shouldThrow(); } catch (NullPointerException success) {} } @@ -368,6 +370,27 @@ } /** + * Deque constructor with <code>null</code> {@link ReentrantLock} argument + * throws NPE. + */ + public void testConstructor7() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque(20,null/*lock*/); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from null Lock throws NPE + */ + public void testConstructor8() { + try { + LinkedBlockingDeque q = new LinkedBlockingDeque((ReentrantLock)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** * Deque transitions from empty to full when elements added */ public void testEmptyFull() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |