同步线程和锁定

时间:2011-07-24 14:17:46

标签: java multithreading scjp

有人可以在对象锁定的上下文中解释这两个例子之间的区别:

public void method1(){
    synchronized(this){
        ....
    }
}

并且

StringBuffer aStringBufferObject = new StringBuffer("A");

public void method2(){
    synchronized(aStringBufferObject){
        ....
    }
}

我知道第一个示例将获取this实例上的锁定,第二个示例将获取aStringBufferObject实例的锁定。但我真的不明白两者的影响或区别。

例如,在第二个示例中,线程是否仍然能够执行synchronized块内的代码,因为锁与'this'实例无关?

我知道同步一个方法或一个代码块会阻止多个线程同时访问该块/方法,但是指定要锁定的对象的目的是什么,以及对象的方式有何不同如上例所示?

3 个答案:

答案 0 :(得分:8)

  

指定要锁定的对象的目的是什么?

通常,在thisClass实例上(对于静态方法)更容易同步。但是,在某些情况下,您需要同步特定对象而不是隐式锁(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){
        ....
    }
}

如果可以确保method1method2的并发执行不违反类不变量,则可以使用拆分锁。这样,您可以提高需要访问同一对象的线程的性能,但会调用不同的方法。


关于你的另一个问题,

  

例如,在第二个示例中,线程是否仍然能够执行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来同步阻止。