令人困惑的Java同步方法,synced(this)和同步类

时间:2018-09-02 00:29:04

标签: java multithreading

由于Java的同步概念,我感到非常困惑。

让我们假设以下课程:

class MyClass {
  public synchronized void foo() { //do something }
  public void bar() {
    synchronized(this) { //do something }
  }
  public void normal() { //do something }
}

据我所知,foobar方法的工作原理相同。

但是,在线程A进入bar方法并通过synchronized(this)同步实例之后,任何线程都可以调用普通方法吗?

据我所知,某些线程可以调用普通方法,而无需调用foo方法。但是我不确定何时调用bar方法,因为它同步了一个实例。

此外,我们假设采用以下方法:

class StaticMyClass {
  public static synchronized void fooStatic() { //do something }
  publi static void barStatic() {
    synchronized(StaticMyClass.class) { //do something }
  }
  public static void normalStatic() { //do something }
}

在这里,有相同的问题。线程A进入临界区(为synchronized(StaticMyClass.class)fooStatic方法之后,任何线程都可以调用normalStatic吗?
我认为fooStaticnormalStatic可以独立调用,而barStaticnormalStatic则不能。如果不对,为什么?

感谢您的帮助。

修改:
我的困惑点是我不确定synchronized(this)是否与synchronized(myClassInstance)相同。

MyClass my = new MyClass();
synchronized(my) {
  //do something, Any other thread can't access my.normal(), is it right?
}

class MyClass {
  public synchronized void foo() { //do something }
  public void bar() {
    synchronized(this) {
      //do something, isn't this same as above synchronized(my)?
    }
  }
  public void normal() { //do something }
}

3 个答案:

答案 0 :(得分:2)

  

据我所知,foobar方法的工作原理相同。

正确。它们都在this上进行同步。

  

线程A输入bar方法并通过synchronized(this)同步实例后,任何线程都可以调用normal方法吗?

是的。正确。

  

据我所知,某些线程可以调用normal方法,而无需调用foo方法。但是我不确定何时调用bar方法。因为它同步了一个实例。

foobar相同。它们都在this上同步。 normal方法未对任何内容进行同步。因此,可以随时随地调用它,并且在方法调用时或在内部都不会阻塞。

在您的术语中,normal方法不是关键部分 1


第二个带有静力学的例子

  

在这里,有同样的问题。在线程A进入临界部分(是synchronized(StaticMyClass.class)fooStatic方法之后,任何线程都可以调用normalStatic吗?

是的。 fooStaticbarStatic都将在StaticMyClass.class上进行同步。

  

我认为,可以分别调用fooStaticnormalStatic,但不能分别调用barStaticnormalStatic

不正确。 normalStatic未被fooStaticbarStatic阻止。

我不确定您在哪里知道normalStatic可能会被阻止……但是这是一个普通的方法调用,并且不会获取任何内部锁,因此无法在锁上对其进行阻止。


您的第三个示例尚不清楚。代码显示了一件事,但是问题提出了不同/不相关的问题。


1-如果(例如)foobar在保持固有锁定的同时被称为normal,可能会造成一些混乱。然后normal代码将有效地放在关键部分,因为调用者持有该锁。但是它(normal)通常不知道这一点。这就是为什么我更喜欢避免使用“关键部分”的术语。

答案 1 :(得分:1)

如果未指定监视器是谁,则使用实例方法,监视器是实例(this),使用静态方法,监视器是类(YourClass.class)。

此代码

public synchronized void foo() { //do something }

与此相同

public void foo() {
   synchronized(this) { //do something }
}

和此代码

public static synchronized void fooStatic() { //do something }

与此相同

public static void fooStatic() {
   synchronized(StaticMyClass.class) { //do something }
}

因此,在两种情况下,foo和bar都是依赖的(同时只能有一个线程),而normal可以独立调用。

答案 2 :(得分:1)

  

但是在线程A进入bar方法并通过Synchronized(this)同步实例之后,任何线程都可以调用普通方法吗?

在同一对象上两次同步方法的调用是不可能交织的。当一个线程正在执行对象的同步方法时,所有其他为同一对象块调用同步方法的线程(挂起执行),直到第一个线程对该对象完成为止。

如果您尝试调用其他不同步的方法,则可以。

  

在线程A进入已同步(StaticMyClass.class)或fooStatic方法的关键部分之后,任何线程都可以调用normalStatic吗?   我认为,可以分别调用fooStatic和normalStatic,但不能单独调用barStatic和normalStatic。如果错了为什么?

可以同步调用其他未同步的方法,但是当您调用barStatic()时,由于正在同步整个类,因此无法调用其他方法。其他线程,必须等到当前线程完成执行。