我应该同步构造函数吗



考虑一个表示简单单元格的类:

class Cell {
    private int x;
    Cell(int x) {
        this.x = x;
    }
    int getX() {
        return x;
    }
    void setX(int x) {
        this.x = x;
    }
}

如果我想使其线程安全,我应该只同步方法还是也同步构造函数?

class Cell {
    private int x;
    Cell(int x) {
        synchronized(this) { // <- Is this synchronization necessary?
            this.x = x;
        }
    }
    synchronized int getX() {
        return x;
    }
    synchronized void setX(int x) {
        this.x = x;
    }
}

如果是,为什么java.util.Vector构造函数中没有synchronized块?

根据JLS#8.8.3

实际上不需要对构造函数进行同步,因为它会锁定正在构建的对象,通常直到对象已经完成了他们的工作。

因此,这意味着引用是在可访问之前同步的。

由于您正在正确同步,因此可以说,只要同步在所述字段上是一致的,那么构造函数中发生的写入将在对象发布之前发生

在您的情况下,由于getX()setX()都是同步的,因此同步是一致的,您不需要在构造函数中同步。


现在,您是否需要在构造函数上使用synchronize(this),正如JLS所提到的,它在您不知情的情况下隐式同步。

这带来了一个重要的切点-您永远不应该允许对对象的引用从其构造函数中转义,因为这将允许访问部分构造的对象。

因此,假设您遵循这条编程的铁定律,您永远不需要同步构造函数,因为在构造函数返回之前,任何方法,无论是并发方法还是其他方法,都无法访问对象。因此,同步毫无逻辑意义。

不,您不需要同步构造函数,因为只要您在构造函数中,引用就不会泄露到另一个线程。

除此之外:

  1. 考虑让你的类不可变。然后不需要同步
  2. 我宁愿不做一个像synchronzid这样的简单类,而是把同步留给类的用户。如果只从一个线程访问同一个对象,则不需要同步

您的情况不需要。

  1. 如果您正在访问可共享数据,则需要使用sych块进行包装

在您的情况下,您正在访问实例变量,由于您在构造函数中,该变量只能由一个线程访问/可见。您将调用构造函数,分配内存,方法调用结束时返回调用方法的唯一指针,这样指针/实例对于线程是唯一的。

一旦收到指针。如果指针/对象变量像这样在多个线程中共享。

Object obj = new Object();
Thread t1 = new Thread(new x(obj)); 
Thread t2 = new Thread(new x(obj));
Class x implements runnable{
 Object obj;
 x (Object obj){
   this.obj = obj;
 }
run() {
 // do some operation on Obj  -
}
}

}

在这种情况下,obj在多个线程之间共享,因此您的实例变量x受竞赛条件约束。因此,您必须确保使用其他方法。

这就是为什么向量构造函数并没有sycn块,而其他方法却有。

假设这个类中有一个静态变量。则需要按同步块进行包装,因为任何一个同步块都可以访问它。

构造函数永远不应该同步,因为我想这是不实用的。(你什么时候需要同时从不同的地方调用同一个构造函数?)

以下是进一步的信息:

最新更新