You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/06/24 03:32:59 UTC
svn commit: r550149 - in /tapestry/tapestry5/trunk/tapestry-ioc/src:
main/java/org/apache/tapestry/ioc/internal/util/
test/java/org/apache/tapestry/ioc/internal/util/
Author: hlship
Date: Sat Jun 23 18:32:58 2007
New Revision: 550149
URL: http://svn.apache.org/viewvc?view=rev&rev=550149
Log:
TAPESTRY-1571: CheckForUpdatesFilter can cause deadlock
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrier.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrierTest.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentTarget.java
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrier.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrier.java?view=diff&rev=550149&r1=550148&r2=550149
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrier.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrier.java Sat Jun 23 18:32:58 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,165 +12,222 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.ioc.internal.util;
-
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-
-/**
- * A barrier used to execute code in a context where it is guarded by read/write locks. In addition,
- * handles upgrading read locks to write locks (and vice versa). Execution of code within a lock is
- * in terms of a {@link Runnable} object (that returns no value), or a {@link Invokable} object
- * (which does return a value).
- */
-public class ConcurrentBarrier
-{
- private final ReadWriteLock _lock = new ReentrantReadWriteLock();
-
- /**
- * This is, of course, a bit of a problem. We don't have an avenue for ensuring that this
- * ThreadLocal is destroyed at the end of the request, and that means a thread can hold a
- * reference to the class and the class loader which loaded it. This may cause redeployment
- * problems (leaked classes and class loaders). Apparently JDK 1.6 provides the APIs to check to
- * see if the current thread has a read lock. So, we tend to remove the TL, rather than set its
- * value to false.
- */
- public static class ThreadBoolean extends ThreadLocal<Boolean>
- {
- @Override
- protected Boolean initialValue()
- {
- return false;
- }
- }
-
- private final ThreadBoolean _threadHasReadLock = new ThreadBoolean();
-
- /**
- * Invokes the object after acquiring the read lock (if necessary). If invoked when the read
- * lock has not yet been acquired, then the lock is acquired for the duration of the call. If
- * the lock has already been acquired, then the status of the lock is not changed.
- * <p>
- * TODO: Check to see if the write lock is acquired and <em>not</em> acquire the read lock in
- * that situation. Currently this code is not re-entrant. If a write lock is already acquired
- * and the thread attempts to get the read lock, then the thread will hang. For the moment, all
- * the uses of ConcurrentBarrier are coded in such a way that reentrant locks are not a problem.
- *
- * @param <T>
- * @param invokable
- * @return the result of invoking the invokable
- */
- public <T> T withRead(Invokable<T> invokable)
- {
- boolean readLockedAtEntry = _threadHasReadLock.get();
-
- if (!readLockedAtEntry)
- {
- _lock.readLock().lock();
-
- _threadHasReadLock.set(true);
- }
-
- try
- {
- return invokable.invoke();
- }
- finally
- {
- if (!readLockedAtEntry)
- {
- _lock.readLock().unlock();
-
- _threadHasReadLock.remove();
- }
- }
- }
-
- /**
- * As with {@link #withRead(Invokable)}, creating an {@link Invokable} wrapper around the
- * runnable object.
- */
- public void withRead(final Runnable runnable)
- {
- Invokable<Void> invokable = new Invokable<Void>()
- {
- public Void invoke()
- {
- runnable.run();
-
- return null;
- }
- };
-
- withRead(invokable);
- }
-
- /**
- * Acquires the exclusive write lock before invoking the Invokable. The code will be executed
- * exclusively, no other reader or writer threads will exist (they will be blocked waiting for
- * the lock). If the current thread has a read lock, it is released before attempting to acquire
- * the write lock, and re-acquired after the write lock is released. Note that in that short
- * window, between releasing the read lock and acquiring the write lock, it is entirely possible
- * that some other thread will sneak in and do some work, so the {@link Invokable} object should
- * be prepared for cases where the state has changed slightly, despite holding the read lock.
- * This usually manifests as race conditions where either a) some parallel unrelated bit of work
- * has occured or b) duplicate work has occured. The latter is only problematic if the operation
- * is very expensive.
- *
- * @param <T>
- * @param invokable
- */
- public <T> T withWrite(Invokable<T> invokable)
- {
- boolean readLockedAtEntry = _threadHasReadLock.get();
-
- if (readLockedAtEntry)
- {
- _lock.readLock().unlock();
-
- _threadHasReadLock.set(false);
- }
-
- _lock.writeLock().lock();
-
- try
- {
- return invokable.invoke();
- }
- finally
- {
- _lock.writeLock().unlock();
-
- if (readLockedAtEntry)
- {
- _lock.readLock().lock();
-
- _threadHasReadLock.set(true);
- }
- else
- {
- _threadHasReadLock.remove();
- }
- }
- }
-
- /**
- * As with {@link #withWrite(Invokable)}, creating an {@link Invokable} wrapper around the
- * runnable object.
- */
- public void withWrite(final Runnable runnable)
- {
- Invokable<Void> invokable = new Invokable<Void>()
- {
- public Void invoke()
- {
- runnable.run();
-
- return null;
- }
- };
-
- withWrite(invokable);
- }
-}
+package org.apache.tapestry.ioc.internal.util;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A barrier used to execute code in a context where it is guarded by read/write locks. In addition,
+ * handles upgrading read locks to write locks (and vice versa). Execution of code within a lock is
+ * in terms of a {@link Runnable} object (that returns no value), or a {@link Invokable} object
+ * (which does return a value).
+ */
+public class ConcurrentBarrier
+{
+ private final ReadWriteLock _lock = new ReentrantReadWriteLock();
+
+ /**
+ * This is, of course, a bit of a problem. We don't have an avenue for ensuring that this
+ * ThreadLocal is destroyed at the end of the request, and that means a thread can hold a
+ * reference to the class and the class loader which loaded it. This may cause redeployment
+ * problems (leaked classes and class loaders). Apparently JDK 1.6 provides the APIs to check to
+ * see if the current thread has a read lock. So, we tend to remove the TL, rather than set its
+ * value to false.
+ */
+ public static class ThreadBoolean extends ThreadLocal<Boolean>
+ {
+ @Override
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ }
+
+ private final ThreadBoolean _threadHasReadLock = new ThreadBoolean();
+
+ /**
+ * Invokes the object after acquiring the read lock (if necessary). If invoked when the read
+ * lock has not yet been acquired, then the lock is acquired for the duration of the call. If
+ * the lock has already been acquired, then the status of the lock is not changed.
+ * <p>
+ * TODO: Check to see if the write lock is acquired and <em>not</em> acquire the read lock in
+ * that situation. Currently this code is not re-entrant. If a write lock is already acquired
+ * and the thread attempts to get the read lock, then the thread will hang. For the moment, all
+ * the uses of ConcurrentBarrier are coded in such a way that reentrant locks are not a problem.
+ *
+ * @param <T>
+ * @param invokable
+ * @return the result of invoking the invokable
+ */
+ public <T> T withRead(Invokable<T> invokable)
+ {
+ boolean readLockedAtEntry = _threadHasReadLock.get();
+
+ if (!readLockedAtEntry)
+ {
+ _lock.readLock().lock();
+
+ _threadHasReadLock.set(true);
+ }
+
+ try
+ {
+ return invokable.invoke();
+ }
+ finally
+ {
+ if (!readLockedAtEntry)
+ {
+ _lock.readLock().unlock();
+
+ _threadHasReadLock.remove();
+ }
+ }
+ }
+
+ /**
+ * As with {@link #withRead(Invokable)}, creating an {@link Invokable} wrapper around the
+ * runnable object.
+ */
+ public void withRead(final Runnable runnable)
+ {
+ Invokable<Void> invokable = new Invokable<Void>()
+ {
+ public Void invoke()
+ {
+ runnable.run();
+
+ return null;
+ }
+ };
+
+ withRead(invokable);
+ }
+
+ /**
+ * Acquires the exclusive write lock before invoking the Invokable. The code will be executed
+ * exclusively, no other reader or writer threads will exist (they will be blocked waiting for
+ * the lock). If the current thread has a read lock, it is released before attempting to acquire
+ * the write lock, and re-acquired after the write lock is released. Note that in that short
+ * window, between releasing the read lock and acquiring the write lock, it is entirely possible
+ * that some other thread will sneak in and do some work, so the {@link Invokable} object should
+ * be prepared for cases where the state has changed slightly, despite holding the read lock.
+ * This usually manifests as race conditions where either a) some parallel unrelated bit of work
+ * has occured or b) duplicate work has occured. The latter is only problematic if the operation
+ * is very expensive.
+ *
+ * @param <T>
+ * @param invokable
+ */
+ public <T> T withWrite(Invokable<T> invokable)
+ {
+ boolean readLockedAtEntry = releaseReadLock();
+
+ _lock.writeLock().lock();
+
+ try
+ {
+ return invokable.invoke();
+ }
+ finally
+ {
+ _lock.writeLock().unlock();
+ restoreReadLock(readLockedAtEntry);
+ }
+ }
+
+ private boolean releaseReadLock()
+ {
+ boolean readLockedAtEntry = _threadHasReadLock.get();
+
+ if (readLockedAtEntry)
+ {
+ _lock.readLock().unlock();
+
+ _threadHasReadLock.set(false);
+ }
+ return readLockedAtEntry;
+ }
+
+ private void restoreReadLock(boolean readLockedAtEntry)
+ {
+ if (readLockedAtEntry)
+ {
+ _lock.readLock().lock();
+
+ _threadHasReadLock.set(true);
+ }
+ else
+ {
+ _threadHasReadLock.remove();
+ }
+ }
+
+ /**
+ * As with {@link #withWrite(Invokable)}, creating an {@link Invokable} wrapper around the
+ * runnable object.
+ */
+ public void withWrite(final Runnable runnable)
+ {
+ Invokable<Void> invokable = new Invokable<Void>()
+ {
+ public Void invoke()
+ {
+ runnable.run();
+
+ return null;
+ }
+ };
+
+ withWrite(invokable);
+ }
+
+ /**
+ * Try to aquire the exclusive write lock and invoke the Runnable. If the write lock is obtained
+ * within the specfied timeout, then this method behaves as {@link #withWrite(Runnable)} and
+ * will return true. If the write lock is not obtained within the timeout then the runnable is
+ * never invoked and the method will return false.
+ *
+ * @param runnable
+ * Runnable object to execute inside the write lock.
+ * @param timeout
+ * Time to wait for write lock.
+ * @param timeoutUnit
+ * Units of timeout.
+ * @return true if lock was obtained & runnabled executed. False otherwise.
+ */
+ public boolean tryWithWrite(final Runnable runnable, long timeout, TimeUnit timeoutUnit)
+ {
+ boolean readLockedAtEntry = releaseReadLock();
+
+ boolean obtainedLock = false;
+
+ try
+ {
+ try
+ {
+ obtainedLock = _lock.writeLock().tryLock(timeout, timeoutUnit);
+
+ if (obtainedLock) runnable.run();
+
+ }
+ catch (InterruptedException e)
+ {
+ obtainedLock = false;
+ }
+ finally
+ {
+ if (obtainedLock) _lock.writeLock().unlock();
+ }
+ }
+ finally
+ {
+ restoreReadLock(readLockedAtEntry);
+ }
+
+ return obtainedLock;
+ }
+
+}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrierTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrierTest.java?view=diff&rev=550149&r1=550148&r2=550149
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrierTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentBarrierTest.java Sat Jun 23 18:32:58 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,142 +12,222 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.ioc.internal.util;
-
+package org.apache.tapestry.ioc.internal.util;
+
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-
-import java.util.List;
-
+
+import java.util.List;
+
import org.apache.tapestry.ioc.internal.util.ConcurrentBarrier;
import org.apache.tapestry.ioc.test.TestBase;
-import org.testng.annotations.Test;
-
-/**
- * Test is structured a bit oddly, since it evolved from when the Concurrence annotation and aspect
- * evolved into the {@link ConcurrentBarrier} utility class.
- */
-@Test(sequential = true)
-public class ConcurrentBarrierTest extends TestBase
-{
- private ConcurrentTarget _target = new ConcurrentTarget();
-
- private static final int THREAD_COUNT = 100;
-
- private static final int THREAD_BLOCK_SIZE = 5;
-
- @Test
- public void read_lock_then_write_lock() throws Exception
- {
- Runnable operation = new Runnable()
- {
- public void run()
- {
- _target.incrementCounter();
- }
- };
-
- runOperation(operation);
- }
-
- @Test
- public void read_lock_inside_write_lock() throws Exception
- {
- Runnable operation = new Runnable()
- {
- public void run()
- {
- // Gets a write lock, then a read lock.
- _target.incrementCounterHard();
- }
- };
-
- runOperation(operation);
- }
-
- @Test(enabled = true)
- public void write_lock_inside_read_lock() throws Exception
- {
- Runnable operation = new Runnable()
- {
- public void run()
- {
- // A read lock method that upgrades to a write lock
-
- _target.incrementIfNonNegative();
- }
- };
-
- runOperation(operation);
- }
-
- @Test(enabled = true)
- public void indirection_between_read_method_and_write_method() throws Exception
- {
- Runnable operation = new Runnable()
- {
- public void run()
- {
-
- // Read lock method invokes other class, that invokes write method.
-
- _target.incrementViaRunnable();
- }
- };
-
- runOperation(operation);
- }
-
- /**
- * Test that locking, especially read lock upgrade and downgrade, work properly when there's
- * more than one object involved.
- */
- @Test
- public void multiple_synchronized_objects() throws Exception
- {
- Runnable operation = new ConcurrentTargetWrapper(_target);
-
- runOperation(operation);
- }
-
- private void runOperation(Runnable operation) throws InterruptedException
- {
- // System.out.println("** Start synchronization");
-
- List<Thread> threads = newList();
- List<Thread> running = newList();
-
- _target.setCounter(0);
-
- for (int i = 0; i < THREAD_COUNT; i++)
- {
-
- Thread t = new Thread(operation);
-
- threads.add(t);
-
- if (threads.size() >= THREAD_BLOCK_SIZE)
- startThreads(threads, running);
- }
-
- startThreads(threads, running);
-
- for (Thread t : running)
- t.join();
-
- assertEquals(_target.getCounter(), THREAD_COUNT);
-
- // System.out.println("** End synchronization");
- }
-
- private void startThreads(List<Thread> threads, List<Thread> running)
- {
- for (Thread t : threads)
- {
- t.start();
- running.add(t);
- }
-
- threads.clear();
- }
-
-}
+import org.testng.annotations.Test;
+
+/**
+ * Test is structured a bit oddly, since it evolved from when the Concurrence annotation and aspect
+ * evolved into the {@link ConcurrentBarrier} utility class.
+ */
+@Test(sequential = true)
+public class ConcurrentBarrierTest extends TestBase
+{
+ private ConcurrentTarget _target = new ConcurrentTarget();
+
+ private static final int THREAD_COUNT = 100;
+
+ private static final int THREAD_BLOCK_SIZE = 5;
+
+ @Test
+ public void read_lock_then_write_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ _target.incrementCounter();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test
+ public void read_lock_inside_write_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // Gets a write lock, then a read lock.
+ _target.incrementCounterHard();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test(enabled = true)
+ public void write_lock_inside_read_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // A read lock method that upgrades to a write lock
+
+ _target.incrementIfNonNegative();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test(enabled = true)
+ public void indirection_between_read_method_and_write_method() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+
+ // Read lock method invokes other class, that invokes write method.
+
+ _target.incrementViaRunnable();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ /**
+ * Test that locking, especially read lock upgrade and downgrade, work properly when there's
+ * more than one object involved.
+ */
+ @Test
+ public void multiple_synchronized_objects() throws Exception
+ {
+ Runnable operation = new ConcurrentTargetWrapper(_target);
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test
+ public void read_lock_then_try_write_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ _target.tryIncrementCounter();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test
+ public void read_lock_inside_try_write_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // Gets a write lock, then a read lock.
+ _target.tryIncrementCounterHard();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+ @Test(enabled = true)
+ public void try_write_lock_inside_read_lock() throws Exception
+ {
+ Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // A read lock method that upgrades to a write lock
+
+ _target.tryIncrementIfNonNegative();
+ }
+ };
+
+ runOperationAndCheckCounter(operation);
+ }
+
+
+ @Test(enabled = true)
+ public void write_lock_timeout_inside_read_lock() throws Exception
+ {
+ final Runnable operation = new Runnable()
+ {
+ public void run()
+ {
+ // A read lock method that upgrades to a write lock
+
+ _target.tryIncrementIfNonNegative();
+ }
+ };
+
+ _target.withRead( new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ runOperation(operation);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ });
+ assertEquals(_target.getCounter(), 0);
+
+ }
+
+
+
+ private void runOperationAndCheckCounter(Runnable operation) throws InterruptedException
+ {
+ runOperation(operation);
+
+ assertEquals(_target.getCounter(), THREAD_COUNT);
+ }
+
+ private void runOperation(Runnable operation)
+ throws InterruptedException
+ {
+ List<Thread> threads = newList();
+ List<Thread> running = newList();
+
+ _target.setCounter(0);
+
+ for (int i = 0; i < THREAD_COUNT; i++)
+ {
+
+ Thread t = new Thread(operation);
+
+ threads.add(t);
+
+ if (threads.size() >= THREAD_BLOCK_SIZE)
+ startThreads(threads, running);
+ }
+
+ startThreads(threads, running);
+
+ for (Thread t : running)
+ t.join();
+ }
+
+ private void startThreads(List<Thread> threads, List<Thread> running)
+ {
+ for (Thread t : threads)
+ {
+ t.start();
+ running.add(t);
+ }
+
+ threads.clear();
+ }
+
+}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentTarget.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentTarget.java?view=diff&rev=550149&r1=550148&r2=550149
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentTarget.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/ConcurrentTarget.java Sat Jun 23 18:32:58 2007
@@ -12,100 +12,141 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.ioc.internal.util;
-
+package org.apache.tapestry.ioc.internal.util;
+
import org.apache.tapestry.ioc.internal.util.ConcurrentBarrier;
-
-public class ConcurrentTarget
-{
- private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
-
- private int _counter;
-
- // Used to check if read locks accumulate when a read lock method calls another read lock method
- public int readCounter()
- {
- return _barrier.withRead(new Invokable<Integer>()
- {
- public Integer invoke()
- {
- return getCounter();
- }
- });
- }
-
- public int getCounter()
- {
- return _barrier.withRead(new Invokable<Integer>()
- {
- public Integer invoke()
- {
- return _counter;
- }
- });
- }
-
- public void incrementCounter()
- {
- _barrier.withWrite(new Runnable()
- {
- public void run()
- {
- _counter++;
- }
- });
- }
-
- public void setCounter(final int counter)
- {
- _barrier.withWrite(new Runnable()
- {
- public void run()
- {
- _counter = counter;
- }
- });
- }
-
- public void incrementIfNonNegative()
- {
- _barrier.withRead(new Runnable()
- {
- public void run()
- {
- if (_counter >= 0)
- incrementCounter();
- }
- });
- }
-
- public void incrementViaRunnable()
- {
- _barrier.withRead(new Runnable()
- {
- public void run()
- {
- Runnable r = new Runnable()
- {
- public void run()
- {
- incrementCounter();
- }
- };
-
- r.run();
- }
- });
- }
-
- public void incrementCounterHard()
- {
- _barrier.withWrite(new Runnable()
- {
- public void run()
- {
- _counter = getCounter() + 1;
- }
- });
- }
-}
+
+import java.util.concurrent.TimeUnit;
+
+public class ConcurrentTarget
+{
+ private final ConcurrentBarrier _barrier = new ConcurrentBarrier();
+
+ private int _counter;
+
+ // Used to check if read locks accumulate when a read lock method calls another read lock method
+ public int readCounter()
+ {
+ return _barrier.withRead(new Invokable<Integer>()
+ {
+ public Integer invoke()
+ {
+ return getCounter();
+ }
+ });
+ }
+
+ public int getCounter()
+ {
+ return _barrier.withRead(new Invokable<Integer>()
+ {
+ public Integer invoke()
+ {
+ return _counter;
+ }
+ });
+ }
+
+ public void incrementCounter()
+ {
+ _barrier.withWrite(new Runnable()
+ {
+ public void run()
+ {
+ _counter++;
+ }
+ });
+ }
+
+ public void setCounter(final int counter)
+ {
+ _barrier.withWrite(new Runnable()
+ {
+ public void run()
+ {
+ _counter = counter;
+ }
+ });
+ }
+
+ public void incrementIfNonNegative()
+ {
+ _barrier.withRead(new Runnable()
+ {
+ public void run()
+ {
+ if (_counter >= 0)
+ incrementCounter();
+ }
+ });
+ }
+
+ public void incrementViaRunnable()
+ {
+ _barrier.withRead(new Runnable()
+ {
+ public void run()
+ {
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ incrementCounter();
+ }
+ };
+
+ r.run();
+ }
+ });
+ }
+
+ public void incrementCounterHard()
+ {
+ _barrier.withWrite(new Runnable()
+ {
+ public void run()
+ {
+ _counter = getCounter() + 1;
+ }
+ });
+ }
+
+ public void tryIncrementCounter()
+ {
+ _barrier.tryWithWrite(new Runnable()
+ {
+ public void run()
+ {
+ _counter++;
+ }
+ },20, TimeUnit.MILLISECONDS);
+ }
+
+ public void tryIncrementCounterHard()
+ {
+ _barrier.tryWithWrite(new Runnable()
+ {
+ public void run()
+ {
+ _counter = getCounter() + 1;
+ }
+ },20,TimeUnit.MILLISECONDS);
+ }
+
+ public void tryIncrementIfNonNegative()
+ {
+ _barrier.withRead(new Runnable()
+ {
+ public void run()
+ {
+ if (_counter >= 0)
+ tryIncrementCounter();
+ }
+ });
+ }
+
+
+ public void withRead(Runnable runnable ) {
+ _barrier.withRead(runnable);
+ }
+}