2013-02-22 8 views
8

コンストラクタ​​は作成できませんが、内部コンストラクタ​​を記述することができます。そのような要件はどのような場合に来るでしょうか? 私は楽しまれています。コンストラクタ内で同期ブロックを使用するとは何ですか?

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 []"; 
    } 
} 

答えて

11

さて、あなたは、コンストラクタ内で新しいスレッドを開始することができます。それは非常に珍しいでしょう - あなたが提供したコードで確かに無意味ですが、起こる可能性があります。

言語は通常、無意味である可能性のあるすべての可能性のあるものを見つけようとはしません。複雑な言語仕様につながります。それはあなたが、コンストラクタの外にthisをリークしている暗示するので、あまりにも、言語のユーザーの一部に思考のいくつかの程度が存在しなければならない...

+0

質問があります。例えば、[this example](http://ideone.com/E6DCMm)のように、コンストラクタからスレッドセーフオブジェクトを安全にパブリッシュする必要があります。それは安全ですか?つまり、 'synchronized(this)'ブロックをコンストラクタ内で使用すると、 'this'オブジェクトがエスケープするかどうか...? –

+0

@ St.Antario:どのようにコンストラクタ内にオブジェクトを公開しているのかわかりません。それを作成していますが、コンストラクターが終了するまでオブジェクトを見ることはできません。あなたが新しい質問をしたいかもしれないように聞こえるかもしれません。 –

6

thisに同期すると、悪い習慣の兆候のようになります。これは、他のコードと同じオブジェクトを同期させることができます。

しかし、他の一般的なロックで同期することは正当な可能性があります。コンストラクタは実際にこのような同期を必要とするコードを呼び出すことを伴います。

+0

非常に興味深い点。あなたは漏れについて説明しませんか?私は、コンストラクタ内の 'synchronized(this)'が 'this'をどのように逃げさせるのか見ていません。例:http://ideone.com/E6DCMm。ここで脱出はどこですか? –

+0

@ St.Antario彼は、「これを同期させる」唯一の理由は漏れだと言っている。しかし、私はそれが常に真実だとは思わない。なぜなら、 'synchronized'はコンストラクターが終了した後に別のスレッドで発生する何かとの出来事前の関係を作るのにも使うことができるからです。この質問に対する私の答えを見てください。 –

0

複数のスレッドがアクセスするコンストラクタの共通データを変更していることがあります。より良い単純なアプローチが好まれるだろうが。

0

通常の状態では、そうする理由はないはずです。

しかし、thisの参照がコンストラクタを "エスケープ"するようにすると(これは当然のことですが)、他の操作を呼び出す前に同期されたブロックが完了するまでクライアントコードを強制的に待たせることができます。例えば

:この例では

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

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

} 

、あなたがsomeService内部criticalSection()を起動する場合は、あなたは、コンストラクタでの同期ブロックが完了するまで待つことを余儀なくされます。

もう一度、これはお勧めしません。thisがコンストラクタをエスケープすることは決して許されません。

0

私が理解する限り、コンストラクタ内の静的フィールドを処理することが重要です。オブジェクトが作成中の場合は、そのオブジェクトを作成しているスレッドのみがこのオブジェクトにアクセスできますが、コンストラクタ内の静的フィールド値が変更された場合、2つの異なるスレッドが同じクラスのオブジェクトを同時に作成して、静的なフィールドに。しかし、使用することをお勧めしますか?ロックの場合

0

これは、コンストラクタで最終的ではないフィールドを確実に公開するために使用できます。

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

別のスレッドが型テストのオブジェクトを受け取り、そしてそれはまたTestのそのインスタンスに同期する場合、このコンストラクタで​​ブロックの終わり、および始まりの間で発生し、前に関係を作成します他のスレッドで​​ブロック:あなたが安全に別のスレッドからのテストのインスタンスを渡すために、同期機構に必要があるため

しかし実際には、これは、ほとんどないに便利です
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. 
     } 
    } 
} 

、および同期メカニズムほぼ確実そのものすでに幸せを紹介していますns-beforeスレッド間の関係。

それでも、非常に固有の並行性コンポーネントで使用することができます。

+0

これが勝つのは、データ競争でも安全な出版です。しかし、それは明示的にロックを取るオブジェクトのレシーバーに依存しているため、上記の基本的な前提を損なう:あなたがコントロールしていないコードに対して確実にしたい。 –

+0

'test.a'がsynchronizedブロックなしで0を出力する方法を知りません...' test'はコンストラクタが実行を終了する前に決して割り当てられないので、 'test'は' null'か 'test.a'です。私は間違っていますか? – Codebender

+0

@ MarcoTopolnikこの質問は、おそらくより良い例があります。http://stackoverflow.com/questions/34672218/object-publication-through-constructor/34672998同じクラスの変数にアクセスするコンストラクタとコードの両方をカプセル化することができます –

関連する問題