2016-09-10 5 views
0

私のメソッドがスレッドセーフであるかどうかは疑いがありますが、逆にスレッドセーフではないことは確かですが、解決策はまだ見つかりませんでした。次 は私のコードです:はオブジェクトモニタで同期されていますが、私の場合はセマフォが良いでしょうか?

class TestLockSingleton 
    { 
     private static TestLockSingleton ourInstance = new TestLockSingleton(); 
    public static TestLockSingleton getInstance() { 
     return ourInstance; 
    } 

    private TestLockSingleton() { 
    } 

    ... 
    private Object LockMonitor= new Object(); 

      interface Listener 
     { 
      void isEnable(boolean result); 
     } 

public void setStatus(int status){ 
    synchronized(LockMonitor){ 
     this.status = status; 
     this.setted = true; 
    } 
} 

     public void isEnable(final Listener listener){ 
      synchronized(LockMonitor){ 
       if(!setted){ 
        LocalBroadcastManager.getInstance(context).registerReceiver(new BroadcastReceiver() { 
        @Override 
        public void onReceive(Context context, Intent intent) { 
         synchronized(LockMonitor){ 
          Bundle bundle = intent.getExtras(); 
          setStatus(bundle.getInt("Status", OFFVALUE)); 
          Listener.isEnable((status==ACTIVEVALUE)?true:false); 
          LocalBroadcastManager.getInstance(context).unregisterReceiver(this); 
         } 
        } 
        },new IntentFilter(MYACTION)); 
       }else{ 
        Listener.isEnable((status==ACTIVEVALUE)?true:false); 
       } 
      } 

     } 
    .... 
    } 

は今私の問題は、私はTestLockSingletonクラス内のメソッドisEnable(最終リスナーリスナー)がスレッドセーフではないと思われるということです。

複数のリスナーを処理する必要はありません。代わりに、メソッドisEnable(最終リスナーリスナー)を呼び出した最後のユーザーがコールバックを受け取るようにする必要があります。

しかし、2つの異なるスレッドがisEnable(最終リスナーリスナー)を呼び出す場合、メソッドを呼び出した最後のスレッドは2つのリスナーコールバックを受信しますか?

編集:私は、「状態」変数がすでにisEnableへ 先例コール(最終リスナーリスナー)からsettedされていない場合にのみ、受信機を登録したい

  • 、:私はこの外挿したコードでやりたいんこれを行うために、私は "設定された"変数を作成し、それを私が状態変数を設定するのと同時にtrueに設定します。

     TestLockSingleton.getInstance().isEnable(
          new Listener() 
        { 
           @Override 
         public void isEnable(boolean result) { 
    
         } 
        }) 
    

    一度に1つのボークスレッド:私はこれを達成したい

  • "をsetted" への同時アクセスを防止するために同期され、 "ステータス" メンバ変数を使用

  • スレッドBは時刻2に同じことをします

    スレッドBはリスナーレスを受信するなぜなら、もし私がそのスレッドBが2つのコールバックを同じ結果で受け取るならば、私は複数のBroadcastReceiverを登録することを防ぎます。

+1

あなたは何を達成しようとしていますか?このコードはそのままではコンパイルされません。ある時点で複数の放送受信機がインストールされないように同期を使用しようとしていますか? –

+0

こんにちは!私の質問を読んでくれてありがとう。私の悪い英語のために申し訳ありません。最初のメッセージを編集して詳しい説明をしました。 私の実際のコードのfaqsimileなので、このコードはコンパイルされません。 – aeroxr1

答えて

1

私は次のようなコードが必要だと思います。

あなたは注意する必要があります。 Listener.isEnableは複数のスレッドから呼び出されます:TestLockingSingleton.isEnableを呼び出すスレッドとメインスレッド。

public class TestLockSingleton { 
    // ... 

    public interface Listener { 
    void isEnable(boolean isActive); 
    } 

    private static TestLockSingleton instance = new TestLockSingleton(); 

    public static TestLockSingleton getInstance() { 
    return instance; 
    } 


    private final Object lock = new Object(); 
    private int status; 
    private boolean enabled; 

    private TestLockSingleton() { 
    } 

    public void setStatus(int status) { 
    synchronized (lock) { 
     this.status = status; 
     this.enabled = true; 
    } 
    } 

    public void isEnable(Context context, final Listener listener) { 
    boolean enabled; 
    boolean active; 
    synchronized (lock) { 
     enabled = this.enabled; 
     active = status == ACTIVEVALUE; 
    } 

    if (enabled) { 
     listener.isEnable(active); 
     return; 
    } 

    LocalBroadcastManager.getInstance(context).registerReceiver(
     new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      int status = intent.getExtras().getInt("Status", OFFVALUE); 
      setStatus(status); 
      listener.isEnable(status == ACTIVEVALUE); 
      LocalBroadcastManager.getInstance(context).unregisterReceiver(this); 
     } 
     }, 
     new IntentFilter(MYACTION)); 
    } 

    // ... 
} 

編集:Listener.isEnableの呼び出し中にロックを保持しているからTestLockSingleton.isEnableを防ぐために。この場合、これが望ましいかどうかは不明です。

+0

このように鉱山のように、いつでも複数の放送受信機が登録されてしまうのを防ぎませんか、間違っていますか? スレッドBは、不幸なケースでは、スレッドAによって登録されたbroadcastReceiverから1つ、それ自体で登録されたbroadcastReceiverに1つ、または間違っています。 – aeroxr1

+1

あなたと私のどちらも、一度に1つのBroadcastReceiverしか登録されないことを保証しません。それをしたいならば、 'this.enabled'を使ってReceiverが登録されていることを示す必要があります。あなたは永続的にBroadcastReceiverを登録し、0人または1人のリスナーだけの登録を許可することを検討しましたか? –

+0

はい、当初私はそのように考えていましたが、ステータス値が到着したときに受信機の登録を解除することが重要です。どのようにして最後のリスナーだけに抵抗を許すことができますか? – aeroxr1

関連する問題