如何使线程等待ReentrantLock释放?

时间:2019-05-16 01:28:51

标签: java multithreading concurrency

如果一个线程获取了一个锁,我希望其他线程跳过尝试获取该锁的过程,而只是等待释放该锁,然后再继续执行。我不希望其他线程在释放锁后获得该锁。

我一直在阅读这个主题,但仍然感到困惑。

请参见下面的以下通用代码段:

private final ReentrantLock reentrantLock = new ReentrantLock();

public void aCoolMethod(){
    if (reentrantLock.tryLock() == true){
        try {
            doSomething();
        } finally {
            reentrantLock.unlock();
        }
    } else {
        // have threads wait until reentrantLock is unlocked
    }
    doSomethingElse();
}

在继续执行之前,如何让进入我的else块的线程等待可重入锁解锁?

2 个答案:

答案 0 :(得分:2)

正如Thilo所述,解决问题的一种更好的方法是让关键部分包含一个线程首先检查的标志。如果尚未设置标志,请在退出关键部分之前解决您的问题并设置标志。如果已设置该标志,那么您知道另一个线程首先到达那里并解决了问题,因此只需退出关键部分。

private final ReentrantLock reentrantLock = new ReentrantLock();
private boolean fixed = false;

public void aCoolMethod(){
    try {
        reentrantLock.lock();

        if (!fixed) {
            doSomething();
        }
    } finally {
        fixed = true;
        reentrantLock.unlock();
    }

    doSomethingElse();
}

或者,没有锁,则可以使用共识对象来确定哪个线程运行doSomething()

private final AtomicBoolean turn = new AtomicBoolean(true);
private volatile boolean done = false;

public void aCoolMethod(){
    if (turn.compareAndSet(true, false)) {
        doSomething();
        done = true;
    } else {
        while (!done) {
          // spin or wait for condition
        }
        doSomethingElse();
    }
}

答案 1 :(得分:-1)

发布最终使用的解决方案,以防其他人遇到类似问题。我选择使用等待通知策略。虽然其他答案很有帮助,但这对我的情况很好,并且很简单。

private final ReentrantLock reentrantLock = new ReentrantLock();

public void aCoolMethod(){
    if (reentrantLock.tryLock()){
        try {
            doSomething();
        } finally {
            reentrantLock.unlock();
            synchronized (reentrantLock) {
                reentrantLock.notifyAll();
            }
        }
    } else {
        // have threads wait until reentrantLock is unlocked
        synchronized (reentrantLock) {
            while(reentrantLock.isLocked()) {
                try {
                    reentrantLock.wait();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    doSomethingElse();
}

编辑:发布测试类,以便其他人可以测试此解决方案。只需复制/粘贴并运行它。见下文:

import java.util.concurrent.locks.ReentrantLock;
import java.lang.Thread;

public class LockTest {

    public static void main(String args[]){
        TestClass testClass = new TestClass();

        Thread thread0 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };
        Thread thread1 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };
        Thread thread2 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };

        thread0.start();
        thread1.start();
        thread2.start();

    }

    public static class TestClass{
        ReentrantLock reentrantLock = new ReentrantLock();

        public void testLock(){
            if (reentrantLock.tryLock()) {
                try {
                    System.out.println("Locking");
                    System.out.println(Thread.currentThread().getName() + " will sleep");
                    Thread.sleep(8000);
                    System.out.println(Thread.currentThread().getName() + " has woken up from sleep!!");
                } catch (InterruptedException i) {
                    System.out.println("Interrupted during sleep");
                } finally {
                    System.out.println("Unlocking");
                    reentrantLock.unlock();
                    System.out.println("Notifying");
                    synchronized (reentrantLock) {
                        reentrantLock.notifyAll();
                    }
                }
            } else {
                synchronized (reentrantLock) {
                    while(reentrantLock.isLocked()) {
                        try {
                            System.out.println(Thread.currentThread().getName() + " will wait");
                            reentrantLock.wait();
                            System.out.println(Thread.currentThread().getName() + " has woken up from wait!!");
                        } catch (InterruptedException i) {
                            System.out.println("Interrupted during wait");
                        }
                    }
                }
            }
            System.out.println(Thread.currentThread().getName() + " has reached the end.");
        }

    }

}