方法同步与对象同步有什么不同?

时间:2012-09-12 23:29:25

标签: java multithreading thread-safety thread-synchronization

  

可能重复:
  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;
    }
}
}

3 个答案:

答案 0 :(得分:6)

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中删除数据然后进行更新。为什么让其他人都被锁定在数据之外?在这种情况下,较低的粒度更好。

现在你可能还记得我之前说的几乎相同。两者之间存在微小的微小差异。 synchronized方法将烘焙指令以同步到字节码中的方法签名。这将使字节码缩短1个字节,因为它不需要进行额外的调用。这可能会产生很小的影响,因为方法字节码中的字节数是决定是否内联的因素之一。尽管有这个细节,我强烈建议将它们视为相同,因为这是一种微观优化,在生产环境中几乎不会发挥显着作用。如果不是这样,那就称它们是完全相同的。

答案 1 :(得分:2)

synchronized实例方法在this上同步。

所以

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

相当于

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

答案 2 :(得分:2)

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) {}
    }
}