我知道同步方法和同步块之间的区别,但我不确定同步块部分。
假设我有这段代码
class Test {
private int x=0;
private Object lockObject = new Object();
public void incBlock() {
synchronized(lockObject) {
x++;
}
System.out.println("x="+x);
}
public void incThis() { // same as synchronized method
synchronized(this) {
x++;
}
System.out.println("x="+x);
}
}
在这种情况下,使用 lockObject 和使用 this 作为锁定有什么区别?对我来说似乎是一样的..
当您决定使用synchronized块时,如何确定哪个对象是锁?
答案 0 :(得分:62)
就我个人而言,我几乎从不锁定“这个”。我通常会锁定一个私有的引用,我知道没有其他代码可以锁定。如果您锁定“this”,那么任何其他知道您的对象的代码可能会选择锁定它。虽然它不太可能发生,但肯定会发生 - 并且可能导致死锁,或者只是过度锁定。
关于你锁定的东西并没有什么特别神奇的东西 - 你可以有效地将它视为一种象征。任何使用相同令牌锁定的人都将尝试获取相同的锁。除非您希望其他代码能够获取相同的锁,否则请使用私有变量。我还鼓励你制作变量final
- 我不记得我曾希望更改锁定变量的情况对象的生命周期。
答案 1 :(得分:11)
当我阅读Java Concurrency In Practice时,我有同样的问题,我想我会在Jon Skeet和spullara提供的答案上添加一些额外的观点。
这是一些示例代码,它会在setValue(int)
方法执行时阻止“快速”getValue()
/ doStuff(ValueHolder)
方法。
public class ValueHolder {
private int value = 0;
public synchronized void setValue(int v) {
// Or could use a sychronized(this) block...
this.value = 0;
}
public synchronized int getValue() {
return this.value;
}
}
public class MaliciousClass {
public void doStuff(ValueHolder holder) {
synchronized(holder) {
// Do something "expensive" so setter/getter calls are blocked
}
}
}
使用this
进行同步的缺点是其他类可以同步对类的引用(当然不是通过this
)。在锁定对象引用时恶意或无意使用synchronized
关键字会导致您的类在并发使用情况下表现不佳,因为外部类可以有效地阻止您的this
- 同步方法,而您没有任何关系可以(在你的班级中)在运行时禁止这个。为了避免这种潜在的陷阱,您可以在private final Object
上同步或使用Lock
中的java.util.concurrent.locks
界面。
对于这个简单的例子,您可以使用AtomicInteger
而不是同步setter / getter。
答案 2 :(得分:5)
Effective Java Second Edition的第67项是避免过度同步,因此我会在私有锁对象上进行同步。
答案 3 :(得分:1)
Java中的每个对象都可以充当监视器。选择一个取决于您想要的粒度。选择'this'的优点和缺点是其他类也可以在同一个监视器上同步。我的建议是避免直接使用synchronize关键字,而是使用java.util.concurrency库中更高级别且具有良好定义语义的构造。这本书从非常着名的专家那里得到了许多很好的建议:
实践中的Java并发 http://amzn.com/0321349601
答案 4 :(得分:0)
在这种情况下,选择锁定哪个对象并不重要。但是必须始终使用相同的对象进行锁定才能实现正确的同步。上面的代码不能确保正确的同步,因为你曾经使用'this'对象作为锁,然后将'lockObject'作为锁。