同步线程和锁定

zig*_*ggy 8 java multithreading scjp

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

public void method1(){
    synchronized(this){
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

StringBuffer aStringBufferObject = new StringBuffer("A");

public void method2(){
    synchronized(aStringBufferObject){
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Vin*_*lds 8

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

通常,thisClass实例上或实例上更容易同步(对于静态方法).但是,在某些情况下,您需要同步特定对象而不是隐式锁(this).此类案件包括:

  • 您希望在不使用的情况下同步对基元的访问this.您只能在Objects上进行同步,因为每个Object都与Java中的隐式监视器相关联.基元没有这样的隐式监视器,因此您需要使用锁定对象.使用包装器类是一个糟糕且不正确的选择,特别是如果您最终修改了受保护块中的锁定对象.
  • 您希望在实际保护关键部分的对象上进行同步,而在同步时则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){
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

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


在你的另一个问题上,

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

在第二个示例中,进入受保护区域的任何线程都必须获取与之关联的锁定aStringBufferObject.如果另一个线程持有该锁,则当前线程将不再继续.指定时this,线程必须获取与当前对象关联的锁.在这两种情况下,线程都必须获得锁定; 这些示例仅在用作锁的对象中有所不同.