有人可以在对象锁定的上下文中解释这两个示例之间的区别:
public void method1(){
synchronized(this){
....
}
}
和
StringBuffer aStringBufferObject = new StringBuffer("A");
public void method2(){
synchronized(aStringBufferObject){
....
}
}
我知道第一个示例将获得
this
实例的锁,第二个示例将获得aStringBufferObject实例的锁。但是我真的不明白两者的作用或区别是什么。例如,在第二个示例中,由于锁与“this”实例无关,线程仍将能够执行同步块(synchronized block)内的代码吗?
我知道同步一个方法或代码块会阻止多个线程同时访问该块/方法,但是指定要锁定的对象的目的是什么,以及在对象中指定对象的方式有何不同上面的例子?
最佳答案
通常,在this
或Class
实例上进行同步更容易(对于静态方法)。但是,在某些情况下,您将需要在特定对象上进行同步,而不是隐式锁定(this
)。此类情况包括:
this
同步对基元的访问。您只能在Object
上进行同步,因为每个Object
与Java中的隐式监视器关联。基元没有此类隐式监视器,因此您需要使用锁对象。使用包装器类是一个糟糕而错误的选择,尤其是当您最终使用modifying the lock object in the guarded block时。 this
上进行同步将无法保证线程安全。例如,如果要同步对在ArrayList
类的实例之间共享的A
实例的访问,则在A
实例上进行同步是没有用的。一个线程可能会创建一个A
的新实例并获得对列表的访问权限,而另一个线程正在对其进行修改。如果使用所有线程都必须争用的其他锁,则可以保护列表;否则,您可以保护列表。此锁可以是与A.class
关联的锁,但也可以是将提供相同保证的任何对象。 以下是拆分锁用法的示例:
private Object method1Lock = new Object();
private Object method2Lock = new Object();
public void method1(){
synchronized(method1Lock){
....
}
}
public void method2(){
synchronized(method2Lock){
....
}
}
当您可以确保并发执行
method1
和method2
不违反类不变式时,可以使用分割锁。这样,您可以提高需要访问同一对象但将调用不同方法的线程之间的性能。关于你的另一个问题,
在第二个示例中,任何进入 protected 区域的线程都必须获取与
aStringBufferObject
关联的锁。如果另一个线程持有该锁,则当前线程将不会继续进行。指定this
时,线程必须获取与当前对象关联的锁。在这两种情况下,线程都必须获得一个锁。这些示例仅在用作锁的对象方面有所不同。