【问题标题】:How to lock with ReentrantLock?如何使用 ReentrantLock 锁定?
【发布时间】:2015-05-08 08:04:38
【问题描述】:

我希望以下测试只打印一次“已锁定”。 但它因此会打印该行。

public class LocKTest {
    @Test
    public void testLock() {
        Lock lock = new ReentrantLock();
        while (true) {
            if (lock.tryLock()) {
                //lock.lock(); same result if I include an explicit lock here
                System.out.println("has been locked");
            }
        }
    }
}

据我了解,tryLock 将尽可能锁定ReentrantLock(即如果尚未锁定)。但显然情况并非如此。

如何设置这样的锁线程安全?

【问题讨论】:

  • 它在while循环中,一旦获得锁,同一个对象再次请求同一个锁,所以它每次都获得锁,它将永远打印has been locked
  • 这就是它被称为可重入的原因

标签: java spring locking


【解决方案1】:

名字是ReentrantLock,这意味着如果你已经拥有锁,你可以re-enter

如果您希望拥有线程块,您可以使用例如带有 1 个(或更多)许可的 Semaphore

【讨论】:

  • 那么我可能误解了这个概念。是否有任何Lock 实现可以满足我的需求?
  • @membersound Semaphore 将是我认为最直接的一个。没有可用的不可重入锁实现。
  • 信号量具有单一许可,重入并不意味着它不是线程安全的。此外,当您锁定时,您是否需要满足一些条件才能继续。你不能只是锁定而不做任何事情
  • 谢谢,Semaphore 似乎是这里最好的解决方案。 @NitinDandriyal 当然,代码只是演示我的问题的一个示例。实际上,我当然要执行一个动作,而不是无限循环。
  • 我建议您查看Condition,您可以将其用作Condition c = lock.newCondition(),然后您可以根据您的操作事件调用c.await()c.notify()(它们的工作方式与等待/在同步块/方法内通知)
【解决方案2】:

引用有关tryLock()的文档(我添加的粗体强调):

如果锁没有被另一个线程持有,则获取锁并立即返回值为true,将锁持有计数设置为1

在这种情况下,当前线程持有锁,所以你可以多次 reenter("re-acquire") 它。如果您要从不同的线程运行循环的每次迭代,第一个将获取锁,而第二个将无法获取它。

【讨论】:

    【解决方案3】:

    考虑到Kayamans answer,您可以实现自己的Lock 类:

    public class Lock {
    
        private boolean isLocked = false;
    
        public synchronized void lock() throws InterruptedException {
            while(isLocked) {
                wait();
            }
            isLocked = true;
        }
    
        public synchronized void unlock() {
            isLocked = false;
            notify();
        }
    }
    

    像这样使用它:

    public class LocKTest {
        @Test
        public void testLock() {
            Lock lock = new Lock();
            while (true) {
                if (lock.lock()) {
                    System.out.println("has been locked"); // prints only once
                }
            }
        }
    }
    

    取自this tutorial的代码示例。

    【讨论】:

    • 没错,但通常java.util.concurrent 包类以更有效的方式实现锁定,避免synchronized
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    相关资源
    最近更新 更多