2016-07-01 6 views
2

私はJavaアプリケーションのWebアプリケーションで列挙型を使用して、シングルトンサービスのimplementaionクラスを持っています。アプリケーションの起動時に一度起動され、アプリケーションがアンデプロイされたときにシャットダウンされます。そしてこれは、クライアントにいくつかのサービスメソッドを提供します。このようなコードにスレッドセーフのバグはありますか?

public enum SingletonService{ 
    INSTANCE; 
    private boolean isStarted; 

    public synchronized void start(){ 
    if(!isStarted){ 
     // do initialization stuff 
     isStarted = true; 
    } 
    } 

    public void stop(){ 
     checkStarted(); 
     // do stop jobs 
     isStarted = false; 
    } 

private synchronized void checkStarted(){ 
    if(!isStarted) 
     throw new RuntimeException("SingletonService is not ready"); 
} 

    public void service(){ 
     checkStarted(); 
     // do service job 
    } 

} 

スレッディングが私のために少し難しいですが、私は私が私のコードでトリッキーなバグを逃したことを心配しています。 startcheckStartedを同期させる必要がありますか?このようなコードで悪いことを教えてください。私はまた知ってほしいjavaのようなことのための共通のパターンがある場合は?理由と

+0

スマートなプログラムであっても、スレッド化は困難です。共有され、変更可能なデータへのアクセスを保護する必要があります。共有データメンバーは1つだけです。あなたは1つ以外のすべての方法を同期しました。私もサービスを同期したいと思う。 – duffymo

+0

@duffymoサービスでcheckStartedが呼び出されましたが、十分ではありませんか? – WestFarmer

+0

@WestFarmerサービスコールを同期させる必要はありません。同期メソッドであるcheckStartedメソッドです。このクラスは、シングルトンパターンを実装する標準的な方法ではないが、スレッドセーフです。 –

答えて

1

2つのコメント:checkStartedはプライベート宣言されて

  1. 。サービスの状態は変わりません。ポイント#2がアドレス指定されている場合は、同期して宣言する必要はありません。
  2. ストップは公開され、サービス状態が変化しています。代わりに同期を宣言する必要があります。 stop/startに同時にアクセスする2つのスレッドは、isStartedに同期してアクセスする必要があります。

    public enum SingletonService{ 
    INSTANCE; 
    private boolean isStarted; 
    
    public synchronized void start(){ 
    if(!isStarted){ 
        // do initialization stuff 
        isStarted = true; 
    } 
    } 
    
    public synchronized void stop(){ 
        checkStarted(); 
        // do stop jobs 
        isStarted = false; 
    } 
    
    private void checkStarted(){ 
        if(!isStarted) 
         throw new RuntimeException("SingletonService is not ready"); 
    } 
    
    public void service(){ 
        checkStarted(); 
        // do service job 
    } 
    
    } 
    
2

コードはスレッドセーフ一度に複数のスレッドから使​​用すると、期待どおりに動作することが保証されている場合です。したがって、この特定のコードがスレッドセーフであるかどうかを判断するのは難しいです。しかし、私は試してみるつもりです。あなたが他の人の中でINSTANCE.service()から呼び出されたINSTANCE.service()から呼び出された場合、service()メソッドは、service()が実行を完了する前にシングルトンが停止しないという前提で安全に進むかもしれないと予想していたと思います。この仮定では、あなたのコードはスレッドセーフではありません。たとえば、stopserviceの両方のメソッドにsynchronizeを追加する必要があります。 @ Guarava Agarwalの答えが示すようにcheckStartedに​​を取り除くことができます。

これを確認するには、2つのスレッドを考えます。スレッドAはINSTANCE.start()の後にINSTANCE.stop()を呼び出し、スレッドBはINSTANCE.service()を呼び出します。現在の同期では、次の実行順序は禁止されていません。

  1. スレッドAはINSTANCE.start()を実行します。 isStartedtrueに設定されます。
  2. スレッドAはINSTANCE.stop()と入力し、INSTANCE.checkStarted()(例外はスローされません)を実行します。
  3. スレッドBはINSTANCE.service()と入力し、INSTANCE.checkStarted()を実行します(例外はスローされません)。
  4. スレッドAが完了INSTANCE.stop()isStartedからfalseに設定します。
  5. スレッドBは、シングルトンがすでに停止しているというサービスの仕事を、当初の想定とは逆に進めます。
関連する問題