Java中复合语句的复制引用同步

Java中复合语句的复制引用同步,java,synchronization,thread-safety,Java,Synchronization,Thread Safety,假设我们有一个对象,其方法/字段在“this”上同步。这个问题实际上是关于“这个”的,因为我想我很难理解“这个”指的是什么 因此,我们的目标是: class A { private Field a; private Field b; public synchronized void doSomething() { //something with a } public synchronized void somethingElse() {

假设我们有一个对象,其方法/字段在“this”上同步。这个问题实际上是关于“这个”的,因为我想我很难理解“这个”指的是什么

因此,我们的目标是:

class A {
    private Field a;
    private Field b;

    public synchronized void doSomething() {
       //something with a
    }

    public synchronized void somethingElse() {
       //do something as with b
    }

}
然后我们有另一个对象或方法,它接受A对象,通过doSomething和somethingElse方法处理A和b。因此,我需要在处理对象时保持状态一致,因此我需要同步。假设这些对象是贴图的值。然后我对这些值进行迭代,然后做我所做的事情。因此,问题是,通过以下方式进行操作是否线程安全:

 for(A aObject : map.values()) {
     synchronized(aObject) {
          aObject.doSomething(); 
          aObject.somethingElse();
     }
 }
如果“this”引用与aObject引用相同,我想我不应该遇到麻烦。但如果我这样做会怎么样:

for(A aObject : map.values()) {
      A anotherReference = aObject;

      synchronized(anotherReference) {
         anotherReference.doSomething(); 
         anotherReference.somethingElse();
      }

}
它仍然是线程安全的吗?我的意思是我可以在锁引用的本地副本上同步吗


注意:这是对我需要在代码中执行的操作的过度简化。

在Java中,我们有两个基本的同步习惯用法:同步方法和同步语句

当您在以下代码中使用第一个习惯用法(同步方法)时:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}
您有两个主要影响:

1) 同一对象上的两个同步方法调用不可能交错。当一个线程为一个对象执行同步方法时,调用同一对象块的同步方法的所有其他线程(暂停执行),直到第一个线程对该对象执行完毕

2) 当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生在之前”关系。这保证了对象状态的更改对所有线程都可见

创建同步代码的另一种方法是使用同步语句。与同步方法不同,同步语句必须指定提供内部锁的对象:

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}
在代码中,您同时使用了这两种习惯用法。然后,您的第一个for循环不需要synchronized(aObject),因为您的类方法已经是synchronized方法了

资料来源:

但是假设您的类方法没有同步。您的第二个代码示例:

for(A aObject : map.values()) {
      A anotherReference = aObject;

      synchronized(anotherReference) {
         anotherReference.doSomething(); 
         anotherReference.somethingElse();
      }

}
仍然有效,因为在Java中,每个对象都有一个与之关联的内在锁。当您调用synchronized(objecto)时,您正在获取与该对象关联的锁:另一个引用,在您的例子中,该引用就是AOObject

让我们考虑两个线程:T1和T2。
如果T1在T2之前调用这个for循环,它将获得与AOObject相关联的内在锁,T2将无法执行相同的操作,直到T1结束这两个方法:doSomeneting()和somethinElse()。

在Java中,我们有两个基本的同步习惯用法:同步方法同步语句

当您在以下代码中使用第一个习惯用法(同步方法)时:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}
您有两个主要影响:

1) 同一对象上的两个同步方法调用不可能交错。当一个线程为一个对象执行同步方法时,调用同一对象块的同步方法的所有其他线程(暂停执行),直到第一个线程对该对象执行完毕

2) 当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生在之前”关系。这保证了对象状态的更改对所有线程都可见

创建同步代码的另一种方法是使用同步语句。与同步方法不同,同步语句必须指定提供内部锁的对象:

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}
在代码中,您同时使用了这两种习惯用法。然后,您的第一个for循环不需要synchronized(aObject),因为您的类方法已经是synchronized方法了

资料来源:

但是假设您的类方法没有同步。您的第二个代码示例:

for(A aObject : map.values()) {
      A anotherReference = aObject;

      synchronized(anotherReference) {
         anotherReference.doSomething(); 
         anotherReference.somethingElse();
      }

}
仍然有效,因为在Java中,每个对象都有一个与之关联的内在锁。当您调用synchronized(objecto)时,您正在获取与该对象关联的锁:另一个引用,在您的例子中,该引用就是AOObject

让我们考虑两个线程:T1和T2。
如果T1在T2之前调用此for循环,它将获取与AOObject相关联的内在锁,T2将无法执行相同的操作,直到T1结束两种方法:doSomeneting()和somethinElse()。

同步监视器属于被引用的对象,而不是引用,因此您的两个
for
循环是等效的,它们都在同一物体上同步

现在是一种同步方法

public synchronized void foo() {
  // do stuff
}
完全等同于

public void foo() {
  synchronized(this) {
    // do stuff
  }
}
所以在循环中

for(A aObject : map.values()) {
    synchronized(aObject) {
         aObject.doSomething(); 
         aObject.somethingElse();
    }
}

同步块锁定的监视器与
doSomething()
doSomethingElse()
方法本身使用的监视器相同。您从同步块中获得的好处是,在这两次调用之间,没有其他线程可以潜入并调用同一实例上的任何一个方法。

同步监视器属于被引用的对象,而不是引用,因此您的两个
for
循环是等效的,它们都在同一物体上同步

现在是一种同步方法

public synchronized void foo() {
  // do stuff
}
完全等同于

public void foo() {
  synchronized(this) {
    // do stuff
  }
}
所以在循环中

for(A aObject : map.values()) {
    synchronized(aObject) {
         aObject.doSomething(); 
         aObject.somethingElse();
    }
}

同步块锁定的监视器与
doSomething()
doSomethingElse()
方法本身使用的监视器相同。从synchronized块中您可以得到的是,在这两次调用之间,没有其他线程可以在同一个实例上潜入并调用这些方法中的任何一个。

您似乎对引用是什么感到困惑,因此我将继续阅读它们。使用同步块时,不是在引用本身上同步,而是在引用所指向的对象实例上同步