9

您能告诉我以下调用是否可重入吗?

public class Foo {

  public synchronized void doSomething() {}

  public synchronized void doAnotherSomething() {}
}

public class Too {

  private Foo foo;

  public synchronized void doToo() {
    foo.doSomething();
    //...other thread interfere here....
    foo.doAnotherSomething();
  }

}

方法doToo()可重入中的 2 次连续调用?我不确定这种情况,因为foo.doSomething()方法获取和释放内在锁,两次调用之间没有嵌套同步。是否存在其他线程可能会在 2 次调用之间干扰的情况?

4

3 回答 3

32

首先,关于Java中的可重入锁:

Java 中的同步块是可重入的。这意味着,如果一个 Java 线程进入一个同步的代码块,从而在该块同步的监视器对象上获得锁,则该线程可以进入在同一个监视器对象上同步的其他 Java 代码块。

取自这里

除非另一个对象具有对私有的引用,否则您描述的两个连续调用 (in doToo) 不会受到干扰,因为要访问,需要锁定。但是,调用不会调用重入,因为每次调用都会获取和释放锁。如果被调用,它们将是可重入的,反之亦然。TooFoofooToodoSomethingdoAnotherSomething

于 2012-08-31T16:42:16.687 回答
5

这完全取决于其他线程正在访问什么。另一个线程可以在这些函数之间接管 CPU 吗?是的。会有比赛条件吗?取决于许多因素。

根据您发布的内容,foo.doSomething 将被锁定在 foo 上,然后被释放,然后在进入 doAnotherSomething 时再次锁定。因此,如果另一个未锁定在同一个 Too 对象上的线程尝试操作 foo,他们将能够在 doSomething 和 doAnotherSomething 之间进行操作。如果每个人在操作底层 foo 对象之前都在同一个 Too 对象上同步,那么 foo 的这两个方法将不会在调用之间进行状态操作,因为 Too 对象方法将阻塞其他线程直到完成。因此,您是否有问题取决于您的其他访问者。

There is no reentrance here from what you posted, but java is ok with reentrant synchronization as Amir posted.

于 2012-08-31T16:47:25.590 回答
4

首先,锁适用于对象,因此需要创建对象然后应用锁。

are 2 continuous invocations in method doToo() reentrant? I

在您的情况下,它们不是 re-entrant 。如果代码如下所示,那么它们将是可重入的。

  public class Foo {

 public synchronized void doSomething() {
        doAnotherSomething();
}

 public synchronized void doAnotherSomething() {}
}

一旦在一个对象上获得了锁,那么在同一个对象上它就可以像上述情况一样遍历。

于 2012-08-31T16:46:05.513 回答