Java同步锁

Abi*_*idi 4 java concurrency synchronized

当我们说使用synchronized关键字锁定一个对象时,它是否意味着我们正在获取整个对象的锁定或仅获取块中存在的代码?

在以下示例中listOne.add是同步的,是否意味着如果另一个线程访问listOne.get它将被阻塞,直到第一个线程离开此块?如果第二个线程在第一个线程仍在同步块中时访问同一对象的实例变量上的listTwo.getlistTwo.add方法,该怎么办?

List<String> listONe = new ArrayList<String>();
List<String> listTwo = new ArrayList<String>();

/* ... ... ... */

synchronized(this) {
    listOne.add(something);
}
Run Code Online (Sandbox Code Playgroud)

Arj*_*jms 6

锁定在您包含在synchronized块中的对象实例上.

但要小心!该对象本质上不会被其他线程锁定.只有执行相同的线程synchronized(obj),其中obj this在您的示例中但在其他线程中也可以是变量引用,等待该锁定.

因此,不执行任何同步语句的线程可以访问"锁定"对象的任何和所有变量,并且您可能会遇到竞争条件.


ext*_*eon 6

鉴于方法:

  public void a(String s) {
    synchronized(this) {
      listOne.add(s);
    }
  }

  public void b(String s) {
    synchronized(this) {
      listTwo.add(s);
    }
  }

  public void c(String s) {
      listOne.add(s);
  }

  public void d(String s) {
      synchronized(listOne) {
        listOne.add(s);
      }
  }
Run Code Online (Sandbox Code Playgroud)

你不能同时调用a和b,因为它们被锁定在同一个锁上.但是,您可以同时调用a和c(显然有多个线程),因为它们没有锁定在同一个锁上.这可能会导致listOne出现问题.

您也可以同时调用a和d,因为d在此上下文中与c没有区别.它不使用相同的锁.

始终使用相同的锁锁定listOne非常重要,并且在没有锁定的情况下不允许访问它.如果listOne和listTwo以某种方式相关并且有时需要同时/原子地更新,则需要一个锁来访问它们.否则2个单独的锁可能会更好.

当然,如果您需要的是并发列表,您可能会使用相对较新的java.util.concurrent类:)