Search in sources :

Example 1 with ReentrantCycleDetectingLock

use of com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock in project guice by google.

the class CycleDetectingLockTest method testSingletonThreadsRuntimeCircularDependency.

/**
   * Verifies that graph of threads' dependencies is not static and is calculated in runtime using
   * information about specific locks.
   *
   * <pre>
   *   T1: Waits on S1
   *   T2: Locks B, sends S1, waits on S2
   *   T1: Locks A, start locking B, sends S2, waits on S3
   *   T2: Unlocks B, start locking A, sends S3, finishes locking A, unlocks A
   *   T1: Finishes locking B, unlocks B, unlocks A
   * </pre>
   *
   * <p>This should succeed, even though T1 was locked on T2 and T2 is locked on T1 when T2 locks A.
   * Incorrect implementation detects a cycle waiting on S3.
   */
public void testSingletonThreadsRuntimeCircularDependency() throws Exception {
    final CyclicBarrier signal1 = new CyclicBarrier(2);
    final CyclicBarrier signal2 = new CyclicBarrier(2);
    final CyclicBarrier signal3 = new CyclicBarrier(2);
    final CycleDetectingLockFactory<String> lockFactory = new CycleDetectingLockFactory<String>();
    final CycleDetectingLock<String> lockA = new ReentrantCycleDetectingLock<String>(lockFactory, "A", new ReentrantLock() {

        @Override
        public void lock() {
            if (Thread.currentThread().getName().equals("T2")) {
                try {
                    signal3.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                assertEquals("T1", Thread.currentThread().getName());
            }
            super.lock();
        }
    });
    final CycleDetectingLock<String> lockB = new ReentrantCycleDetectingLock<String>(lockFactory, "B", new ReentrantLock() {

        @Override
        public void lock() {
            if (Thread.currentThread().getName().equals("T1")) {
                try {
                    signal2.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
                    signal3.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                assertEquals("T2", Thread.currentThread().getName());
            }
            super.lock();
        }
    });
    Future<Void> firstThreadResult = Executors.newSingleThreadExecutor().submit(new Callable<Void>() {

        @Override
        public Void call() throws Exception {
            Thread.currentThread().setName("T1");
            signal1.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
            assertTrue(lockA.lockOrDetectPotentialLocksCycle().isEmpty());
            assertTrue(lockB.lockOrDetectPotentialLocksCycle().isEmpty());
            lockB.unlock();
            lockA.unlock();
            return null;
        }
    });
    Future<Void> secondThreadResult = Executors.newSingleThreadExecutor().submit(new Callable<Void>() {

        @Override
        public Void call() throws Exception {
            Thread.currentThread().setName("T2");
            assertTrue(lockB.lockOrDetectPotentialLocksCycle().isEmpty());
            signal1.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
            signal2.await(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
            lockB.unlock();
            assertTrue(lockA.lockOrDetectPotentialLocksCycle().isEmpty());
            lockA.unlock();
            return null;
        }
    });
    firstThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
    secondThreadResult.get(DEADLOCK_TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) CycleDetectingLockFactory(com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory) CyclicBarrier(java.util.concurrent.CyclicBarrier) ReentrantCycleDetectingLock(com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock)

Aggregations

CycleDetectingLockFactory (com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory)1 ReentrantCycleDetectingLock (com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock)1 CyclicBarrier (java.util.concurrent.CyclicBarrier)1 ReentrantLock (java.util.concurrent.locks.ReentrantLock)1