tl;dr - 外部同步使您容易受到攻击(有意或无意),并且还迫使您进行可能不必要的锁定检查。在这个答案的最底部还有书呆子的好信息。
同步方法几乎与同步方法相同(见底部):
synchroinzed void foo() {
}
void foo() {
synchronized(this) {
}
}
通过使方法本身不是synchronized
,您可以让自己锁定任何东西Object
,而不仅仅是this
。我个人建议在 internal 上同步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 个字节,因为它不需要进行额外的调用。这可能会产生很小的影响,因为方法字节码中的字节数是确定是否内联的因素之一。尽管有这些细节,我强烈建议将它们视为相同,因为这是一种微优化,在生产环境中几乎不会发挥重要作用。当它们不是相同时,将其称为相同是不完整的。