在构造函数中使用synchronized块有什么用?

时间:2013-02-22 10:15:17

标签: java synchronization

我们不能创建构造函数synchronized但可以在构造函数中编写synchronized。在什么情况下这样的要求会来? 我很开心。

package com.simple;
public class Test {
    public Test() {
        synchronized (this) {
            System.out.println("I am called ...");
        }
    }

    public static void main(String[] args) {
        Test test=new Test();   
        System.out.println(""+test);
    }

    @Override
    public String toString() {
        return "Test []";
    }
}

7 个答案:

答案 0 :(得分:11)

好吧,你可以在构造函数中启动一个新线程。这将是非常不寻常的 - 当然在您提供的代码中它将毫无意义 - 但它可能会发生。

语言通常不会尝试找到你可能做的每件事都没有意义 - 它会导致非常复杂的语言规范。语言使用者也必须有一定程度的思考......

答案 1 :(得分:6)

this上进行同步将是不良做法的标志,因为这意味着您将this从构造函数中泄露出来:这是您可以在同一对象上同步其他代码的唯一方法

然而,在其他一些常见的锁上同步可能是合法的:构造函数确实涉及调用一些需要这种同步的代码。

答案 2 :(得分:0)

可能是您正在更改多个线程访问的构造函数中的一些常见数据。虽然更好,更简单的方法是首选。

答案 3 :(得分:0)

在正常情况下,你没有理由这样做。

但是,如果你让this引用“转义”构造函数(当然这是不好的做法),那么你可能想强制客户端代码在调用其他代码之前等待synchronized块完成操作

例如:

class C {
    public C() {
        // ....
        synchronized(this) {
            someService.doSomethingWith(this);
            // some other critical stuff...
        }
    }

    public synchronized void criticalSection() {
        // ...
    }

}

在这个例子中,如果你在criticalSection()内调用someService,你将被迫等到构造函数中的synchronized块完成。

但是,不建议这样做,你绝不允许this转义构造函数。

答案 4 :(得分:0)

据我所知,如果你处理构造函数中的静态字段,那么它是至关重要的。当对象正在构建时,只有创建它的线程才能访问此对象,但是如果构造函数中的静态字段值发生更改,则可能是一个问题,因为两个不同的线程可以同时创建同一类的对象,从而导致冲突相关到静态字段。但不确定使用 this 来锁定

是否是个好主意

答案 5 :(得分:0)

它可用于确保在构造函数中安全发布非final字段。

public class Test {
    int a;
    public Test() {
        synchronized (this) {
            a = 5;
        }
    }

如果另一个线程收到一个Test类型的对象,并且它也在Test的那个实例上同步,那么这会在构造函数中synchronized块的结尾之间创建一个before-before关系,以及另一个帖子中synchronized块的开头:

public class InOneThread {
    public void run() {
        InAnotherThread.test = new Test();
    }
}

public class InAnotherThread {
     public static Test test;

     public void run() {
         if (test == null) {
             // Because assignment to `test` wasn't safely published, the
             // field could be null even if it was assigned "earlier" in real
             // time.
             return;
         }
         synchronized(test) {
             System.out.println(test.a); 
             // If no more modifications were made to 'a', this prints 5
             // (guaranteed). Without the synchronized blocks, this could 
             // print 0 (zero) or 5.
         }
     }
}

然而在实践中,这几乎从来没有用,因为你需要同步机制来安全地将Test的实例从一个线程传递到另一个线程,并且同步机制本身几乎肯定已经引入了线程之间的先发生关系。 / p>

它仍然可以在一些高度特定的并发组件中使用。

答案 6 :(得分:0)

我认为Java灵活性可以做到这一点,因为在构造函数内部,您几乎可以将所有内容作为常规方法(Methods vs Constructors in Java)进行,但是如果这样做的话,这是一种不好的做法。 这是一个很好的实践问题,我们不应该在构造函数中使用同步块,在任何情况下都不能在构造函数中做得更好。