了解锁定范围

时间:2015-07-14 11:27:49

标签: java multithreading reentrantlock

从这个link,我理解“由于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怎么办?这不会使事情变得复杂。

我认为在从函数返回控件之前,应该在函数本身中获取并释放锁。我的理解是否正确?

2 个答案:

答案 0 :(得分:5)

回答第一个问题:

  

如果有人在我执行时只调用method2怎么办?   method1 / method2对?这不会使事情变得复杂。

假设另一个线程调用unlock()对象上的ReentrantLock方法,然后IllegalMonitorStateException将被抛出。因为线程没有获取锁定,当它尝试解锁时,它会获得异常 对获取锁定的第一个线程的执行或锁定没有任何影响。

  • 相同主题:

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

    • 锁定:如果锁定由另一个线程保持,则当前线程将被禁用以进行线程调度,并且在获取锁定之前处于休眠状态,此时锁定保持计数设置为1。
    • 解锁:如果不同的线程在没有持有锁时尝试unlock,则抛出IllegalMonitorStateException。

这就是ReentrantLock锁定和解锁要求你拥有try-catch或throw机制的原因,因为它会抛出异常。

请阅读以下ReentrantLock#unlock()

的摘录
  

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

回答第二个问题:

  

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

这是ReentrantLock的全部目的,您可以将锁定机制扩展到其他方法,而使用synchronized块和方法则无法做到这一点。请参阅下面的ReentrantLock

  

具有相同基本行为的重入互斥锁定   语义作为使用synchronized访问的隐式监视器锁   方法和陈述,但具有扩展功能

答案 1 :(得分: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()

虽然在实践中我会认为编写将锁定范围限制为单个方法或方法的一部分的代码会更容易和更清晰。