有人可以在对象锁定的上下文中解释这两个例子之间的区别:
public void method1(){
synchronized(this){
....
}
}
并且
StringBuffer aStringBufferObject = new StringBuffer("A");
public void method2(){
synchronized(aStringBufferObject){
....
}
}
我知道第一个示例将获取this
实例上的锁定,第二个示例将获取aStringBufferObject实例的锁定。但我真的不明白两者的影响或区别。
例如,在第二个示例中,线程是否仍然能够执行synchronized块内的代码,因为锁与'this'实例无关?
我知道同步一个方法或一个代码块会阻止多个线程同时访问该块/方法,但是指定要锁定的对象的目的是什么,以及对象的方式有何不同如上例所示?
答案 0 :(得分:8)
指定要锁定的对象的目的是什么?
通常,在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
的并发执行不违反类不变量,则可以使用拆分锁。这样,您可以提高需要访问同一对象的线程的性能,但会调用不同的方法。
关于你的另一个问题,
例如,在第二个示例中,线程是否仍然能够执行synchronized块内的代码,因为锁与'this'实例无关?
在第二个示例中,进入受保护区域的任何线程都必须获取与aStringBufferObject
关联的锁定。如果另一个线程持有该锁,则当前线程将不再继续。指定this
时,线程必须获取与当前对象关联的锁。在这两种情况下,线程都必须获得锁定;示例仅在用作锁的对象中有所不同。
答案 1 :(得分:2)
在对象上进行同步意味着在同一对象上同步的其他块必须等待。例如:
public void methodA() {
synchronized(obj) {
//Do one job
}
}
public void methodB() {
synchronized(obj) {
//Do another job
}
}
如果您在一个帖子中拨打methodA()
,然后在另一个帖子中拨打methodB()
,methodB()
将在methodA()
完成之前完成。
答案 2 :(得分:2)
synchronized
块是一个监视器,它不包含锁定和解锁互斥锁的详细信息。因为Java中的每个对象都有一个内部锁(请参阅Object
类的源代码),所以当使用synchronized
语句时,JVM将帮助您同步关键部分。您也可以使用包java.util.concurrent.locks
中的ReentrantLock来同步阻止。