【问题标题】:What is different between method synchronized vs object synchronized ? [duplicate]方法同步与对象同步有什么不同? [复制]
【发布时间】:2012-09-06 00:28:06
【问题描述】:

可能重复:
synchronized block vs synchronized method?

如果有人可以帮助我举例说明方法同步与对象同步之间有什么不同?,那就太好了。

方法同步示例

public class MyClassExample {
private int i;
public synchronized void increment(){
    i = i + 1;
}
}

对象同步示例

public class MyClassExample {
private int i;
Object writeLock = new Object();
 public void increment(){
    synchronized(writeLock) {
        i = i + 1;
    }
}
}

【问题讨论】:

    标签: java multithreading thread-safety thread-synchronization


    【解决方案1】:

    tl;dr - 外部同步使您容易受到攻击(有意或无意),并且还迫使您进行可能不必要的锁定检查。在这个答案的最底部还有一些书呆子的好信息。

    同步方法几乎相同(见底部)以同步:

    synchroinzed void foo() {
    
    }
    
    void foo() {
        synchronized(this) {
    
        }
    }
    

    通过使方法本身不是synchronized,您允许自己锁定任何Object,而不仅仅是this。我个人建议在内部Object 上同步,就像这样

    private final Object foolock = new Object();
    
    void foo() {
        synchronzied(foolock) {
    
        }
    }
    

    原因是,如果你使用synchronized 方法,它会有效地锁定this,其他人可以synchronize 锁定你,并将你锁定在Object 之外!想象一下:

    class FooDoer {
        // removed! using synchronized methods instead
        //final Object foolock = new Object();
    
        synchronized void foo() {
    
        }
    }
    
    // thread 1 - attacker
    FooDoer f = new FooDoer();
    globalMap.put("TheFoo",f);
    synchronized(f) {
        while(true); // haha!
    }
    
    // thread 2 - victim
    FooDoer f = globalMap.get("TheFoo");
    f.foo(); // locked, because Thread 1 has locked us out!
    

    这会让您面临拒绝服务攻击。这不好!通过将锁设置为内部,您作为课程的作者可以准确控制谁可以锁定您对象的哪些区域以及在什么条件下。

    另一个问题是您可能没有要检查的受保护数据。例如:

    synchronized void foo() {
        if(expensiveAccessCheck()) {
            update();
        }
    }
    
    void foo() {
        if(expensiveAccessCheck()) {
            synchronized(foolock) {
                update();
            }
        }
    }
    

    在这种情况下,您不必让其他人在您坐在那里转动车轮时等待。也许您正在从 URL 中抓取数据,然后进行更新。为什么要让其他人远离数据?在这种情况下,粒度越低越好。

    现在您可能还记得我之前说的几乎相同。两者之间有一个微小的,微小的,微小的差异。同步方法会将同步指令直接烘焙到字节码中的方法签名中。这将使字节码缩短 1 个字节,因为它不需要进行额外的调用。这可能会产生很小的影响,因为方法的字节码中的字节数是确定是否内联的因素之一。尽管有这些细节,我强烈建议将它们视为相同,因为这是一种微优化,在生产环境中几乎不会发挥重要作用。当它们不是相同时,将其称为相同是不完整的。

    【讨论】:

      【解决方案2】:

      synchronized 实例方法在 this 上同步。

      所以

      public synchronized void increment(){
          i = i + 1;
      }
      

      等价于

      public void increment(){
          synchronized (this) {
              i = i + 1;
          }
      }
      

      【讨论】:

      • 感谢柯克回答了这个问题。我知道同步方法和同步(this)之间的区别。但我想了解更多关于同步方法与同步(对象定义)的信息。
      • syncrhonized(this) 和 synchronized(other object) 之间的唯一区别是您正在同步的对象。
      • 换句话说,每个 Java 对象都有一个隐藏的锁字段,synchronized 语句/块可以获取。所有 Java synchronized 方法和块都获取某个对象的锁定字段。它们的区别仅在于它们如何决定在哪个对象上执行此操作。
      • 它没有隐藏。这是this 对象。事实上,这是使用它的一个非常危险的地方,那就是任何人都可以获得该显示器。我的回答解决了这种危险以及其他危险。
      • @corsiKa:我并不是说 object 是隐藏的。我是说 field 是隐藏的。隐藏,我的意思是只有 synchronized 语句和块可以访问它 - 您不能使用 . 运算符访问该字段。
      【解决方案3】:

      Java 语言规范writes:

      同步方法在执行之前获取监视器(第 17.1 节)。

      对于类(静态)方法,使用与该方法的类的 Class 对象关联的监视器。

      对于实例方法,使用与this(调用该方法的对象)关联的监视器。

      和

      这些是同步语句(第 14.19 节)可以使用的相同监视器。

      因此,代码:

      class Test {
          int count;
          synchronized void bump() {
              count++;
          }
          static int classCount;
          static synchronized void classBump() {
              classCount++;
          }
      }
      

      效果完全一样:

      class BumpTest {
          int count;
          void bump() {
              synchronized (this) { count++; }
          }
          static int classCount;
          static void classBump() {
              try {
                  synchronized (Class.forName("BumpTest")) {
                      classCount++;
                  }
              } catch (ClassNotFoundException e) {}
          }
      }
      

      【讨论】:

      • 感谢您的回答。但我的问题不同。问题是我想了解更多关于同步方法与同步(对象定义)的信息。
      • 您的问题有何不同?既然它们具有“完全相同的效果”,我可以给出什么客观标准来支持其中一个?
      猜你喜欢
      • 2013-08-06
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 2011-05-22
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      相关资源
      最近更新 更多