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);        
+    }
+}