2011-01-20 5 views
2

私は、ブロックキューから読み込んでいたスレッドの制御について、thisに質問していました。それは私が一緒に行くことを選んだソリューションではありませんでしたが、いくつかの人々は、特別な「ポイズンピル」または「センチネル」の値がそのようにようにそれをシャットダウンするようにキューに追加されることが示唆された:値のないオブジェクト

public class MyThread extends Thread{ 
    private static final Foo STOP = new Foo(); 
    private BlockingQueue<Foo> blockingQueue = new LinkedBlockingQueue<Foo>(); 

    public void run(){ 
     try{ 
      Foo f = blockingQueue.take(); 
      while(f != STOP){ 
       doSomethingWith(f); 
       f = blockingQueue.take(); 
      } 
     } 
     catch(InterruptedException e){ 

     } 
    } 

    public void addToQueue(Foo f) throws InterruptedException{ 
     blockingQueue.put(f); 
    } 

    public void stop() throws InterruptedException{ 
     blockingQueue.put(STOP); 
    } 
} 

私が好きなもののこのアプローチでは、STOPフィールドにどのような値を使用するかわからないため、使用しないことにしました。正の整数を挿入することがわかっている場合、負の数を制御値として使用できますが、Fooはかなり複雑なクラスです。それは不変なので、いくつかの引数を取るコンストラクタを持っています。引数を持たないコンストラクタを追加するには、いくつかのフィールドを初期化しないかnullにする必要があります。Fooは、MyThreadと一緒に使用されるだけではありません。同様に、ダミーの値をメインのコンストラクタに入れると、いくつかのフィールドとコンストラクタのパラメータ自体が重要なオブジェクトであるため、この問題が発生します。

私は単に防御的にプログラミングしていますか?オブジェクトを使用可能にするためのセッターがない場合でも、クラスに引数のないコンストラクタを追加することについて心配する必要があります(他のプログラマがそのコンストラクタを使用しないほど賢明であると仮定します)。引数のないコンストラクタまたは少なくとも値以外の値を持てない場合は、Fooのデザインが壊れています - すべてのメソッドでif(someField == null){throw new RuntimeException();}のチェックを行う方が良いでしょうか?

答えて

1

空のコンストラクタを使用しないことは正しいと思います。 Fooがそのような複雑なクラスである場合、完全なオブジェクトを使用することは論理的ではないようです。

nullを追加することができます。それは良い方法だと思う。

別の方法として、インターフェイスを実装することもできます。 IBlockableQueueObject?これはfooオブジェクトとSTOP記号で実装できます。唯一のことは、STOPでない場合は、インターフェイスをFooにキャストする必要があることです。

0

You は、使用可能なインスタンスにならない引数のないコンストラクタを持つことが心配です。

Fooのデザインはうまくいくと思います。ドキュメントで特に許可されていない限り、私は通常、コンストラクタにnullを渡すことはできません。特に、不変クラスを持つ。

2

このデザインの利点と、ループを停止する必要があることを示す単純なブール型変数の違いはわかりません。

本当にこのデザインにしたい場合は、私は引数なしのプライベートなコンストラクタを作成し、静的なSTOP Fooを作成することをお勧めします。このような。

public class Foo { 

    public static final Foo STOP = new Foo(); 
    ... fields 

    private Foo(){} 
    public Foo(...){ 
    ... 
    } 

    ... 

} 

public class MyThread extends Thread{ 
    private static final Foo STOP = new Foo(); 
    private BlockingQueue<Foo> blockingQueue = new LinkedBlockingQueue<Foo>(); 

    public void run(){ 
     try{ 
      Foo f = blockingQueue.take(); 
      while(f != STOP){ 
       doSomethingWith(f); 
       f = blockingQueue.take(); 
      } 
     } 
     catch(InterruptedException e){ 

     } 
    } 

    public void addToQueue(Foo f) throws InterruptedException{ 
     blockingQueue.put(f); 
    } 

    public void stop() throws InterruptedException{ 
     blockingQueue.put(Foo.STOP); 
    } 
} 

これは、無効なコンストラクタをまだ公開していないという利点があります。

不都合な点は、Fooクラスが、ある場合にはそれが「毒薬」として使用されていることを知っていることです。別の欠点は、STOPオブジェクトが矛盾している可能性があることです。あなたはUnsupportedOperationExceptionまたは何かでメソッドを無効にするから匿名サブクラスを作ることができます。あなたはその後、BlockingQueue<Wrapped<Foo>>にポイズンピルとしてnull値を渡すために使用することができます

public class Wrapped<T> { 
    private final T value; 

    public Wrapped(T value) { 
     this.value = value; 
    } 

    public T get() { return value; } 
} 

1

別のオプションは、このような汎用的なラッパーではFooをラップすることです。

関連する問題