簡體   English   中英

Java Concurrency:具有共享訪問權限的成對鎖

[英]Java Concurrency: Paired locks with shared access

我正在尋找以下並發語義的Java實現。 除了對稱之外,我想要類似於ReadWriteLock東西,即讀取和寫入兩者可以在許多線程之間共享,但是read不包括write, 反之亦然

  1. 有兩個鎖,讓我們稱它們為A和B.
  2. 鎖A是共享的,即可能有多個線程同時保存它。 鎖B也是共享的,可能有多個線程同時保存它。
  3. 如果任何線程持有鎖A,則沒有線程可能占用B - 嘗試取B的線程將阻塞,直到所有持有A的線程都釋放A.
  4. 如果任何線程持有鎖B,則沒有線程可能需要A - 嘗試取A的線程將阻塞,直到所有持有B的線程都釋放B.

是否有現成的庫類可以實現這一目標? 目前我使用ReadWriteLock近似了所需的功能,因為幸運的是,在鎖B的上下文中完成的任務有點罕見。 雖然它感覺像是一個黑客,它可能會影響我的程序在重負載下的性能。

簡短回答:

在標准庫中,沒有什么比你需要的更好。

答案很長:

要輕松實現自定義Lock您應該將其子類化或委托給AbstractQueuedSynchronizer

以下代碼是實現您需要的非公平鎖定的示例,包括一些(非耗盡)測試。 我稱之為LeftRightLock是因為您的要求具有二元性質。

這個概念非常簡單:

AbstractQueuedSynchronizer公開了一個方法,使用Compare和swap慣用法( compareAndSetState(int expect,int update) )原子地設置int的狀態,我們可以使用公開狀態保持持有鎖的線程的計數,將其設置為正正在保持Right鎖的情況下的值,或者在保持Left鎖的情況下為負值。

比我們只是做以下條件確定: -你可以鎖定Left只有當內部狀態AbstractQueuedSynchronizerzero或負-你可以鎖定Right只有當內部狀態AbstractQueuedSynchronizerzero或正

LeftRightLock.java


import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Lock;

/**
 * A binary mutex with the following properties:
 *
 * Exposes two different {@link Lock}s: LEFT, RIGHT.
 *
 * When LEFT is held other threads can acquire LEFT but thread trying to acquire RIGHT will be
 * blocked. When RIGHT is held other threads can acquire RIGHT but thread trying to acquire LEFT
 * will be blocked.
 */
public class LeftRightLock {

    public static final int ACQUISITION_FAILED = -1;
    public static final int ACQUISITION_SUCCEEDED = 1;

    private final LeftRightSync sync = new LeftRightSync();

    public void lockLeft() {
        sync.acquireShared(LockSide.LEFT.getV());
    }

    public void lockRight() {
        sync.acquireShared(LockSide.RIGHT.getV());
    }

    public void releaseLeft() {
        sync.releaseShared(LockSide.LEFT.getV());
    }

    public void releaseRight() {
        sync.releaseShared(LockSide.RIGHT.getV());
    }

    public boolean tryLockLeft() {
        return sync.tryAcquireShared(LockSide.LEFT) == ACQUISITION_SUCCEEDED;
    }

    public boolean tryLockRight() {
        return sync.tryAcquireShared(LockSide.RIGHT) == ACQUISITION_SUCCEEDED;
    }

    private enum LockSide {
        LEFT(-1), NONE(0), RIGHT(1);

        private final int v;

        LockSide(int v) {
            this.v = v;
        }

        public int getV() {
            return v;
        }
    }

    /**
     * <p>
     * Keep count the count of threads holding either the LEFT or the RIGHT lock.
     * </p>
     *
     * <li>A state ({@link AbstractQueuedSynchronizer#getState()}) greater than 0 means one or more threads are holding RIGHT lock. </li>
     * <li>A state ({@link AbstractQueuedSynchronizer#getState()}) lower than 0 means one or more threads are holding LEFT lock.</li>
     * <li>A state ({@link AbstractQueuedSynchronizer#getState()}) equal to zero means no thread is holding any lock.</li>
     */
    private static final class LeftRightSync extends AbstractQueuedSynchronizer {


        @Override
        protected int tryAcquireShared(int requiredSide) {
            return (tryChangeThreadCountHoldingCurrentLock(requiredSide, ChangeType.ADD) ? ACQUISITION_SUCCEEDED : ACQUISITION_FAILED);
        }    

        @Override
        protected boolean tryReleaseShared(int requiredSide) {
            return tryChangeThreadCountHoldingCurrentLock(requiredSide, ChangeType.REMOVE);
        }

        public boolean tryChangeThreadCountHoldingCurrentLock(int requiredSide, ChangeType changeType) {
            if (requiredSide != 1 && requiredSide != -1)
                throw new AssertionError("You can either lock LEFT or RIGHT (-1 or +1)");

            int curState;
            int newState;
            do {
                curState = this.getState();
                if (!sameSide(curState, requiredSide)) {
                    return false;
                }

                if (changeType == ChangeType.ADD) {
                    newState = curState + requiredSide;
                } else {
                    newState = curState - requiredSide;
                }
                //TODO: protect against int overflow (hopefully you won't have so many threads)
            } while (!this.compareAndSetState(curState, newState));
            return true;
        }    

        final int tryAcquireShared(LockSide lockSide) {
            return this.tryAcquireShared(lockSide.getV());
        }

        final boolean tryReleaseShared(LockSide lockSide) {
            return this.tryReleaseShared(lockSide.getV());
        }

        private boolean sameSide(int curState, int requiredSide) {
            return curState == 0 || sameSign(curState, requiredSide);
        }

        private boolean sameSign(int a, int b) {
            return (a >= 0) ^ (b < 0);
        }

        public enum ChangeType {
            ADD, REMOVE
        }
    }
}

LeftRightLockTest.java


import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class LeftRightLockTest {


    int logLineSequenceNumber = 0;
    private LeftRightLock sut = new LeftRightLock();

    @Test(timeout = 2000)
    public void acquiringLeftLockExcludeAcquiringRightLock() throws Exception {
        sut.lockLeft();


        Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockRight());
        assertFalse("I shouldn't be able to acquire the RIGHT lock!", task.get());
    }

    @Test(timeout = 2000)
    public void acquiringRightLockExcludeAcquiringLeftLock() throws Exception {
        sut.lockRight();
        Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockLeft());
        assertFalse("I shouldn't be able to acquire the LEFT lock!", task.get());
    }

    @Test(timeout = 2000)
    public void theLockShouldBeReentrant() throws Exception {
        sut.lockLeft();
        assertTrue(sut.tryLockLeft());
    }

    @Test(timeout = 2000)
    public void multipleThreadShouldBeAbleToAcquireTheSameLock_Right() throws Exception {
        sut.lockRight();
        Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockRight());
        assertTrue(task.get());
    }

    @Test(timeout = 2000)
    public void multipleThreadShouldBeAbleToAcquireTheSameLock_left() throws Exception {
        sut.lockLeft();
        Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> sut.tryLockLeft());
        assertTrue(task.get());
    }

    @Test(timeout = 2000)
    public void shouldKeepCountOfAllTheThreadsHoldingTheSide() throws Exception {

        CountDownLatch latchA = new CountDownLatch(1);
        CountDownLatch latchB = new CountDownLatch(1);


        Thread threadA = spawnThreadToAcquireLeftLock(latchA, sut);
        Thread threadB = spawnThreadToAcquireLeftLock(latchB, sut);

        System.out.println("Both threads have acquired the left lock.");

        try {
            latchA.countDown();
            threadA.join();
            boolean acqStatus = sut.tryLockRight();
            System.out.println("The right lock was " + (acqStatus ? "" : "not") + " acquired");
            assertFalse("There is still a thread holding the left lock. This shouldn't succeed.", acqStatus);
        } finally {
            latchB.countDown();
            threadB.join();
        }

    }

    @Test(timeout = 5000)
    public void shouldBlockThreadsTryingToAcquireLeftIfRightIsHeld() throws Exception {
        sut.lockLeft();

        CountDownLatch taskStartedLatch = new CountDownLatch(1);

        final Future<Boolean> task = Executors.newSingleThreadExecutor().submit(() -> {
            taskStartedLatch.countDown();
            sut.lockRight();
            return false;
        });

        taskStartedLatch.await();
        Thread.sleep(100);

        assertFalse(task.isDone());
    }

    @Test
    public void shouldBeFreeAfterRelease() throws Exception {
        sut.lockLeft();
        sut.releaseLeft();
        assertTrue(sut.tryLockRight());
    }

    @Test
    public void shouldBeFreeAfterMultipleThreadsReleaseIt() throws Exception {
        CountDownLatch latch = new CountDownLatch(1);

        final Thread thread1 = spawnThreadToAcquireLeftLock(latch, sut);
        final Thread thread2 = spawnThreadToAcquireLeftLock(latch, sut);

        latch.countDown();

        thread1.join();
        thread2.join();

        assertTrue(sut.tryLockRight());

    }

    @Test(timeout = 2000)
    public void lockShouldBeReleasedIfNoThreadIsHoldingIt() throws Exception {
        CountDownLatch releaseLeftLatch = new CountDownLatch(1);
        CountDownLatch rightLockTaskIsRunning = new CountDownLatch(1);

        Thread leftLockThread1 = spawnThreadToAcquireLeftLock(releaseLeftLatch, sut);
        Thread leftLockThread2 = spawnThreadToAcquireLeftLock(releaseLeftLatch, sut);

        Future<Boolean> acquireRightLockTask = Executors.newSingleThreadExecutor().submit(() -> {
            if (sut.tryLockRight())
                throw new AssertionError("The left lock should be still held, I shouldn't be able to acquire right a this point.");
            printSynchronously("Going to be blocked on right lock");
            rightLockTaskIsRunning.countDown();
            sut.lockRight();
            printSynchronously("Lock acquired!");
            return true;
        });

        rightLockTaskIsRunning.await();

        releaseLeftLatch.countDown();
        leftLockThread1.join();
        leftLockThread2.join();

        assertTrue(acquireRightLockTask.get());
    }

    private synchronized void printSynchronously(String str) {

        System.out.println(logLineSequenceNumber++ + ")" + str);
        System.out.flush();
    }

    private Thread spawnThreadToAcquireLeftLock(CountDownLatch releaseLockLatch, LeftRightLock lock) throws InterruptedException {
        CountDownLatch lockAcquiredLatch = new CountDownLatch(1);
        final Thread thread = spawnThreadToAcquireLeftLock(releaseLockLatch, lockAcquiredLatch, lock);
        lockAcquiredLatch.await();
        return thread;
    }

    private Thread spawnThreadToAcquireLeftLock(CountDownLatch releaseLockLatch, CountDownLatch lockAcquiredLatch, LeftRightLock lock) {
        final Thread thread = new Thread(() -> {
            lock.lockLeft();
            printSynchronously("Thread " + Thread.currentThread() + " Acquired left lock");
            try {
                lockAcquiredLatch.countDown();
                releaseLockLatch.await();
            } catch (InterruptedException ignore) {
            } finally {
                lock.releaseLeft();
            }

            printSynchronously("Thread " + Thread.currentThread() + " RELEASED left lock");
        });
        thread.start();
        return thread;
    }
}

我不知道任何你想要的圖書館。 即使有這樣一個庫,它也沒什么價值,因為每次你的請求改變時,庫就停止了魔術。

這里的實際問題是“如何使用自定義規范實現自己的鎖?”

Java為名為AbstractQueuedSynchronizer工具提供了工具。 它有大量的文檔。 除了文檔之外,您可能希望查看CountDownLatchReentrantLock源並將它們用作示例。

對於您的特定請求,請參閱下面的代碼,但要注意它是1)不公平2)未經測試

public class MultiReadWriteLock implements ReadWriteLock {

    private final Sync sync;
    private final Lock readLock;
    private final Lock writeLock;

    public MultiReadWriteLock() {
        this.sync = new Sync();
        this.readLock = new MultiLock(Sync.READ, sync);
        this.writeLock = new MultiLock(Sync.WRITE, sync);
    }

    @Override
    public Lock readLock() {
        return readLock;
    }

    @Override
    public Lock writeLock() {
        return writeLock;
    }

    private static final class Sync extends AbstractQueuedSynchronizer {

        private static final int READ = 1;
        private static final int WRITE = -1;

        @Override
        public int tryAcquireShared(int arg) {
            int state, result;
            do {
                state = getState();
                if (state >= 0 && arg == READ) {
                    // new read
                    result = state + 1;
                } else if (state <= 0 && arg == WRITE) {
                    // new write
                    result = state - 1;
                } else {
                    // blocked
                    return -1;
                }
            } while (!compareAndSetState(state, result));
            return 1;
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            int state, result;
            do {
                state = getState();
                if (state == 0) {
                    return false;
                }
                if (state > 0 && arg == READ) {
                    result = state - 1;
                } else if (state < 0 && arg == WRITE) {
                    result = state + 1;
                } else {
                    throw new IllegalMonitorStateException();
                }
            } while (!compareAndSetState(state, result));
            return result == 0;
        }
    }

    private static class MultiLock implements Lock {

        private final int parameter;
        private final Sync sync;

        public MultiLock(int parameter, Sync sync) {
            this.parameter = parameter;
            this.sync = sync;
        }

        @Override
        public void lock() {
            sync.acquireShared(parameter);
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireSharedInterruptibly(parameter);
        }

        @Override
        public boolean tryLock() {
            return sync.tryAcquireShared(parameter) > 0;
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return sync.tryAcquireSharedNanos(parameter, unit.toNanos(time));
        }

        @Override
        public void unlock() {
            sync.releaseShared(parameter);
        }

        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException(
                "Conditions are unsupported as there are no exclusive access"
            );
        }
    }
}

怎么樣

class ABSync {

    private int aHolders;
    private int bHolders;

    public synchronized void lockA() throws InterruptedException {
        while (bHolders > 0) {
            wait();
        }
        aHolders++;
    }

    public synchronized void lockB() throws InterruptedException {
        while (aHolders > 0) {
            wait();
        }
        bHolders++;
    }

    public synchronized void unlockA() {
        aHolders = Math.max(0, aHolders - 1);
        if (aHolders == 0) {
            notifyAll();
        }
    }

    public synchronized void unlockB() {
        bHolders = Math.max(0, bHolders - 1);
        if (bHolders == 0) {
            notifyAll();
        }
    }
}

更新:至於“公平”(或者說,非飢餓),OP的要求沒有提到它。 為了實現OPs要求+某種形式的公平/非飢餓,應該明確指定(你認為什么是公平的,當當前主導和非主導鎖的請求流進來時它應該如何表現)。 實現它的方法之一是:

class ABMoreFairSync {

    private Lock lock = new ReentrantLock(true);
    public final Part A, B;

    public ABMoreFairSync() {
        A = new Part();
        B = new Part();
        A.other = B;
        B.other = A;
    }

    private class Part {
        private Condition canGo = lock.newCondition();
        private int currentGeneration, lastGeneration;
        private int holders;
        private Part other;

        public void lock() throws InterruptedException {
            lock.lockInterruptibly();
            try {
                int myGeneration = lastGeneration;
                if (other.holders > 0 || currentGeneration < myGeneration) {
                    if (other.currentGeneration == other.lastGeneration) {
                        other.lastGeneration++;
                    }
                    while (other.holders > 0 || currentGeneration < myGeneration) {
                        canGo.await();
                    }
                }
                holders++;
            } finally {
                lock.unlock();
            }
        }

        public void unlock() throws InterruptedException {
            lock.lockInterruptibly();
            try {
                holders = Math.max(0, holders - 1);
                if (holders == 0) {
                    currentGeneration++;
                    other.canGo.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }
}

用作:

 sync.A.lock();
 try {
     ...
 } finally {
     sync.A.unlock();
 }

這里幾代人的想法取自清單14.9中的 “Java Concurrency in Practice”。

我的第n個試圖做一個簡單的公平實施后,我想我明白為什么我找不到“互斥鎖對”另一個庫/例如:它需要一個非常具體的用戶情況。 正如OP所提到的,你可以通過ReadWriteLock獲得很長的路要走,只有當快速連續有很多鎖請求時,公平的鎖對才有用(否則你可能會使用一個普通的鎖)。

下面的實施更多的是“許可分配器”:它不是可重入的。 它可以重新進入(如果沒有,我擔心我沒能使代碼簡單易讀)但它需要對各種情況進行一些額外的管理(例如,一次線程鎖定A兩次,仍然需要解鎖A兩次並解鎖-method需要知道什么時候沒有更多的鎖定未完成)。 當一個線程鎖定A並想要鎖定B時拋出死鎖錯誤的選項可能是個好主意。

主要思想是存在一個“主動鎖定”,只有在沒有(請求)鎖定時才能通過鎖定方法進行更改,並且當主動鎖定未完成時,可以通過解鎖方法進行更改。 其余的基本上是保持鎖定請求的數量並使線程等待,直到可以更改主動鎖定。 使線程等待涉及使用InterruptedException並在那里做出妥協:我找不到適用於所有情況的良好解決方案(例如應用程序關閉,一個被中斷的線程等)。

我只做了一些基本的測試(最后的測試類),需要更多的驗證。

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A pair of mutual exclusive read-locks: many threads can hold a lock for A or B, but never A and B.
 * <br>Usage:<pre>
 * PairedLock plock = new PairedLock();
 * plock.lockA();
 * try {
 *     // do stuff
 * } finally {
 *     plock.unlockA();
 * }</pre>
 * This lock is not reentrant: a lock is not associated with a thread and a thread asking for the same lock 
 * might be blocked the second time (potentially causing a deadlock).
 * <p> 
 * When a lock for A is active, a lock for B will wait for all locks on A to be unlocked and vice versa.
 * <br>When a lock for A is active, and a lock for B is waiting, subsequent locks for A will wait 
 * until all (waiting) locks for B are unlocked.
 * I.e. locking is fair (in FIFO order).
 * <p>
 * See also
 * <a href="http://stackoverflow.com/questions/41358436">stackoverflow-java-concurrency-paired-locks-with-shared-access</a>
 * 
 * @author vanOekel
 *
 */
public class PairedLock {

    static final int MAX_LOCKS = 2;
    static final int CLOSE_PERMITS = 10_000;

    /** Use a fair lock to keep internal state instead of the {@code synchronized} keyword. */
    final ReentrantLock state = new ReentrantLock(true);

    /** Amount of threads that have locks. */
    final int[] activeLocks = new int[MAX_LOCKS];

    /** Amount of threads waiting to receive a lock. */
    final int[] waitingLocks = new int[MAX_LOCKS];

    /** Threads block on a semaphore until locks are available. */
    final Semaphore[] waiters = new Semaphore[MAX_LOCKS];

    int activeLock;
    volatile boolean closed;

    public PairedLock() {
        super();
        for (int i = 0; i < MAX_LOCKS; i++) {
            // no need for fair semaphore: unlocks are done for all in one go.
            waiters[i] = new Semaphore(0);
        }
    }

    public void lockA() throws InterruptedException { lock(0); }
    public void lockB() throws InterruptedException { lock(1); }

    public void lock(int lockNumber) throws InterruptedException {

        if (lockNumber < 0 || lockNumber >= MAX_LOCKS) {
            throw new IllegalArgumentException("Lock number must be 0 or less than " + MAX_LOCKS);
        } else if (isClosed()) {
            throw new IllegalStateException("Lock closed.");
        }
        boolean wait = false;
        state.lock();
        try {
            if (nextLockIsWaiting()) {
                wait = true;
            } else if (activeLock == lockNumber) {
                activeLocks[activeLock]++;
            } else if (activeLock != lockNumber && activeLocks[activeLock] == 0) {
                // nothing active and nobody waiting - safe to switch to another active lock
                activeLock = lockNumber;
                activeLocks[activeLock]++;
            } else {
                // with only two locks this means this is the first lock that needs an active-lock switch.
                // in other words:
                // activeLock != lockNumber && activeLocks[activeLock] > 0 && waitingLocks[lockNumber] == 0
                wait = true;
            }
            if (wait) {
                waitingLocks[lockNumber]++;
            }
        } finally {
            state.unlock();
        }
        if (wait) {
            waiters[lockNumber].acquireUninterruptibly();
            // there is no easy way to bring this lock back into a valid state when waiters do no get a lock.
            // so for now, use the closed state to make this lock unusable any further.
            if (closed) {
                throw new InterruptedException("Lock closed.");
            }
        }
    }

    protected boolean nextLockIsWaiting() {
        return (waitingLocks[nextLock(activeLock)] > 0);
    }

    protected int nextLock(int lockNumber) {
        return (lockNumber == 0 ? 1 : 0);
    }

    public void unlockA() { unlock(0); }
    public void unlockB() { unlock(1); }

    public void unlock(int lockNumber) {

        // unlock is called in a finally-block and should never throw an exception.
        if (lockNumber < 0 || lockNumber >= MAX_LOCKS) {
            System.out.println("Cannot unlock lock number " + lockNumber);
            return;
        }
        state.lock();
        try {
            if (activeLock != lockNumber) {
                System.out.println("ERROR: invalid lock state: no unlocks for inactive lock expected (active: " + activeLock + ", unlock: " + lockNumber + ").");
                return;
            }
            activeLocks[lockNumber]--;
            if (activeLocks[activeLock] == 0 && nextLockIsWaiting()) {
                activeLock = nextLock(lockNumber);
                waiters[activeLock].release(waitingLocks[activeLock]);
                activeLocks[activeLock] += waitingLocks[activeLock];
                waitingLocks[activeLock] = 0;
            } else if (activeLocks[lockNumber] < 0) {
                System.out.println("ERROR: to many unlocks for lock number " + lockNumber);
                activeLocks[lockNumber] = 0;
            }
        } finally {
            state.unlock();
        }
    }

    public boolean isClosed() { return closed; }

    /**
     * All threads waiting for a lock will be unblocked and an {@link InterruptedException} will be thrown.
     * Subsequent calls to the lock-method will throw an {@link IllegalStateException}.
     */
    public synchronized void close() {

        if (!closed) {
            closed = true;
            for (int i = 0; i < MAX_LOCKS; i++) {
                waiters[i].release(CLOSE_PERMITS);
            }
        }
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName());
        sb.append("=").append(this.hashCode());
        state.lock();
        try {
            sb.append(", active=").append(activeLock).append(", switching=").append(nextLockIsWaiting());
            sb.append(", lockA=").append(activeLocks[0]).append("/").append(waitingLocks[0]);
            sb.append(", lockB=").append(activeLocks[1]).append("/").append(waitingLocks[1]);
        } finally {
            state.unlock();
        }
        return sb.toString();
    }

}

測試類(YMMV - 在我的系統上工作正常,但由於線程的啟動和運行速度更快或更慢,可能會在您的系統上死鎖):

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PairedLockTest {

    private static final Logger log = LoggerFactory.getLogger(PairedLockTest.class);

    public static final ThreadPoolExecutor tp = (ThreadPoolExecutor) Executors.newCachedThreadPool();

    public static void main(String[] args) {

        try {
            new PairedLockTest().test();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            tp.shutdownNow();
        }
    }

    PairedLock mlock = new PairedLock();

    public void test() throws InterruptedException {

        CountDownLatch start = new CountDownLatch(1);
        CountDownLatch done = new CountDownLatch(2);
        mlock.lockA();
        try {
            logLock("la1 ");
            mlock.lockA();
            try {
                lockAsync(start, null, done, 1);
                await(start);
                logLock("la2 ");
            } finally {
                mlock.unlockA();
            }
            lockAsync(null, null, done, 0);
        } finally {
            mlock.unlockA();
        }
        await(done);
        logLock();
    }

    void lockAsync(CountDownLatch start, CountDownLatch locked, CountDownLatch unlocked, int lockNumber) {

        tp.execute(() -> {
            countDown(start);
            await(start);
            //log.info("Locking async " + lockNumber);
            try {
                mlock.lock(lockNumber);
                try {
                    countDown(locked);
                    logLock("async " + lockNumber + " ");
                } finally {
                    mlock.unlock(lockNumber);
                    //log.info("Unlocked async " + lockNumber);
                    //logLock("async " + lockNumber + " ");
                }
                countDown(unlocked);
            } catch (InterruptedException ie) {
                log.warn(ie.toString());
            }
        });
    }

    void logLock() {
        logLock("");
    }

    void logLock(String msg) {
        log.info(msg + mlock.toString());
    }

    static void countDown(CountDownLatch l) {
        if (l != null) {
            l.countDown();
        }
    }

    static void await(CountDownLatch l) {

        if (l == null) {
            return;
        }
        try {
            l.await();
        } catch (InterruptedException e) {
            log.error(e.toString(), e.getCause());
        }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM