7

从这个链接,我了解到“由于 lock() 和 unlock() 方法调用是显式的,我们可以将它们移动到任何地方,建立任何锁定范围,从一行代码到跨越多个方法的范围”

所以我从上面的陈述中理解的是

public class Test {
    Lock l = new ReentrantLock();

    void myMethod1() {
        l.lock();
        // Do my stuff here
    }

    void myMethod2() {
        // Do more stuff here
        l.unlock();
    }
}

所以基本上1可以依次调用method1和method2,并假设调用是线程安全的。

我不确定是否如上面所说的那样是真的。

如果有人在我已经在执行 method1/method2 对时调用了 method2 怎么办?是不是把事情复杂化了。

我认为在函数返回控制之前,应该在函数本身中获取和释放锁。我的理解正确吗?

4

3 回答 3

5

回答第一个问题:

如果有人在我已经在执行 method1/method2 对时调用了 method2 怎么办?是不是把事情复杂化了。

假设另一个线程调用对象unlock()上的方法,那么将被抛出。因为线程没有获得锁,当它试图解锁时,它会得到异常。它不会对获取锁的第一个线程的执行或锁定产生任何影响。ReentrantLockIllegalMonitorStateException

  • 相同的线程:

    • 锁:如果再次获取锁的同一线程尝试获取锁,则锁计数器递增。
    • 解锁:如果获取锁的同一个线程尝试解锁,则锁计数器递减,一旦锁计数器变为 0,线程就会释放锁。
  • 不同的线程:

    • 锁:如果锁被另一个线程持有,那么当前线程将被禁用以进行线程调度,并处于休眠状态,直到获得锁为止,此时锁持有计数设置为 1。
    • 解锁:如果不同的线程试图unlock在它没有持有锁时尝试,则抛出 IllegalMonitorStateException。

这就是ReentrantLocklock 和 unlock 要求您使用 try-catch 或 throw 机制的原因,因为它会抛出异常。

阅读以下摘录自 ReentrantLock#unlock()

如果当前线程是这个锁的持有者,那么持有计数就会递减。如果保持计数现在为零,则释放锁。 如果当前线程不是该锁的持有者,则抛出 {@link IllegalMonitorStateException}

回答第二个问题:

我认为在函数返回控制之前,应该在函数本身中获取和释放锁。我的理解正确吗?

这就是 的全部目的ReentrantLock,您可以将锁定机制扩展到其他方法,这是同步块和方法无法做到的。从ReentrantLock见下文

一种可重入互斥锁,其基本行为和语义与使用同步方法和语句访问的隐式监视器锁相同,但具有扩展功能

于 2015-07-14T12:18:10.183 回答
3

如果有人在我已经在执行 method1/method2 对时调用了 method2 怎么办?是不是把事情复杂化了。

java.util.concurrent.locks.Lock是一种比 更强大的机制synchronized。电动工具很危险。谨慎使用它们。

有关详细信息,请参阅@hagrawal 的答案。

于 2015-07-14T12:43:19.247 回答
1

请考虑以下示例:

public class Test {
    ...
    public void method1() {
       l.lock();
       ...
    }

    public void method2() {
       l.lock();
       ...
       while (l.isHeldByCurrentThread()) {
         l.unlock();
       }
    }
}

这种设置意味着一旦线程 A 调用method1(),线程 B 在调用任何方法时都会阻塞,直到线程 A 调用method2()。因此,锁定范围跨越零次或多次调用 ,method1()然后是一次调用method2().

尽管在实践中,我认为编写将锁定范围限制为单个方法或方法的一部分的代码要容易得多,也更简洁。

于 2015-07-14T11:38:23.407 回答