【问题标题】:Does lock Lock the whole object?lock 锁定整个对象吗?
【发布时间】:2019-02-10 01:47:42
【问题描述】:
class Resource{
  public Lock lock = new ReentrantLock();

  public void A(){
    lock.lock();
    try{ .. }
    finally{
      lock.unlock();
    }
  }

  public void B(){
    lock.lock();
    try{ .. }
    finally{
      lock.unlock();
    }

  }


  public void C(){
    ... //Nothing to do with lock here
  }
}

现在假设我有 3 个线程 T1, T2, T3 和一个名为 resourceResource 实例。

首先运行的是T1 calls resource.A()。现在,假设 resource.A() 需要 1500 分钟,如果 T2 在第 100 分钟内调用 resource.B()(意味着来自 T1 的调用正在运行),会发生什么?

当我执行lock.lock() 时,它是锁定了对象还是锁定了方法

谢谢

【问题讨论】:

  • Lock 锁住锁。

标签: java multithreading concurrency operating-system


【解决方案1】:

锁由线程获得。所以如果一个线程 X 持有锁,其他线程直到被 X 释放后才能获得锁。

在你的情况下,方法B在方法A释放锁之前无法获得锁。

【讨论】:

  • 好的,我明白了,所以如果T2 调用resource.B(),它会等到T1 放弃lock
  • 你是对的。如果锁的主人不放弃锁,那么锁将永远无法被其他人使用。
  • 好的,还有一个问题。 T2 是否可以调用resource.C(),方法C() 对锁没有任何作用,所以如果resource.A() 正在运行,由T1 调用并由T1 锁定,可以T2 调用@ 987654332@中途没有问题?
  • 是的,它可以随时运行resource.C(),因为它对锁没有任何作用。
【解决方案2】:

首先运行的是 T1 调用 resource.a()。现在,假设 resource.a() 需要 1500 分钟,如果 T2 在第 100 分钟内调用 resource.b()(意味着来自 T1 的调用正在运行),会发生什么?

T2 会被阻塞,直到 T1 调用 resource.b() 释放锁。在这种情况下,它将被阻止 1400 分钟。

当我执行lock.lock() 时,它是锁定了对象还是锁定了方法?

也不是。

您没有锁定 Resource 实例:

  1. Resource 实例有一个 intrinsic 锁...这里没有使用。
  2. 其他调用resource.c()的线程不会被阻塞。

您实际上并没有锁定方法。锁定在方法内部。例如,方法a 或方法b 可以在调用lock.lock() 或释放它之后之前 做一些事情。

您实际上所做的是获得了ReentrantLock 对象的锁定。 在这种情况下,三分之二的方法使用锁定对象,因此您实际上锁定了这些方法的相关部分不同线程的调用。

但是,如果调用是由同一个线程进行的(例如,如果 a() 调用了 b()),那么第二次调用将不会被阻塞。 (这就是本文中“可重入”的意思。)

【讨论】:

  • 感谢您提供如此好的答案。 “但是,如果调用是由同一个线程进行的(例如,如果 a() 调用了 b()),那么第二次调用将不会被阻塞。(这就是“可重入”在这种情况下的含义。)”——我是这里有点困惑。所以说T1 调用resource.A()T1 获得了锁,如果resource.A() 调用resource.B() 即使resource.B() 中也有lock.lock() 也不会成为问题?这是如何运作的?谢谢
  • 1) 请尊重 Java 命名约定。这些方法应称为abc。不是ABC
  • 2) 就像我说的,这就是可重入的意思。如果一个线程持有一个锁,然后在同一个锁对象上调用lock(),则实现说“继续……你已经持有那个锁”。在引擎盖下,它只是增加一个计数器。并在相应的lock.unlock() 中递减它
  • 其实还有一个问题。对象的内在锁是什么意思?我阅读了 Oracle 的文档,但作为初学者,我发现它非常混乱。你能提供一个简单的解释吗?我的意思是,T1 现在不拥有resource 的内在锁吗?
  • 不。内在锁是您在(例如)Resource 上使用synchronized(this) { ... } 锁定的锁。
【解决方案3】:

是锁定了对象还是锁定了方法?

两者都没有。它锁定了对象的intrinsic monitor

一个常见的菜鸟错误是认为如果线程 A 在某个对象 o 上同步,那么其他线程将无法使用或修改对象 o。这根本不是真的。线程 A 通过进入 synchronized(o) 块来阻止的唯一事情是,它阻止其他线程同时在同一个对象上同步。

如果你想确保一次只有一个线程可以使用或修改一个对象,那么你必须确保每个你的代码使用或修改它的地方都包裹在synchronized中在同一个对象上同步的块。


一些程序员更喜欢使用单独的私有锁对象:

private static final Object lock = new Object();

public void mymethod(...) {
    synchronized(lock) {
        ...access to this is protected by lock...
    }
}

优点是,它拒绝了其他类弄乱保护你的类的私有数据的锁的能力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多