2016-09-10 1 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); 
       } 
      } 

     } 
    .... 
    } 

Теперь моя проблема заключается в том, что я думаю, что метод isEnable (конечный Слушатель Слушатель) внутри класса TestLockSingleton не THREADSAFE.

Я не хочу обрабатывать более одного слушателя, вместо этого я должен быть уверен, что последний, который вызвал метод isEnable (последний прослушиватель прослушивателя), получит обратный вызов.

Но если два разных вызова потокаEnable (последний прослушиватель прослушивателя), последний, вызвавший метод, получит два обратных вызова прослушивателя?

EDIT: Что я хочу сделать с этим экстраполировать код:

  • Я хочу зарегистрировать приемник, только если «статус» переменная уже не выставиться от прецедента вызова isEnable (конечный Слушатель слушателя), для этого я создаю «установленную» переменную, и я установил ее в true в то же время, когда я установил переменную состояния.
  • Я использую синхронизирована для предотвращения одновременного доступа к «выставиться» и «статус» переменной
  • член я хочу сделать это:

    Нитки во время 1 Invoke:

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

    Резьба B делает то же самое во время 2

    Я бы хотел, чтобы только нить B получала приемник resu lt, я бы запретил регистрировать более одного BroadcastREceiver, потому что если я делаю этот поток B, получаю два обратных вызова с тем же результатом.

+1

Можете ли вы сказать, что вы пытаетесь достичь? Этот код, как он есть, не будет компилироваться. Вы пытаетесь использовать синхронизацию, чтобы предотвратить установку одного приемника вещания в любой момент времени? –

+0

Привет! Спасибо, что прочитал мой вопрос. Извините за мой плохой английский. Я редактировал первое сообщение с большим количеством объяснений. Этот код не компилируется, потому что это только факсимиле моего реального кода. – 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)); 
    } 

    // ... 
} 

Отредактировано: предотвратить TestLockSingleton.isEnable от проведения блокировки во время вызова Listener.isEnable. Неясно, желательно ли это в этом случае.

+0

Этот способ, как у шахты, не позволяет регистрировать более одного вещательного приемника в любой момент времени, или я ошибаюсь? Таким образом, поток В в неудачном случае он может получить два обратных вызова слушателя: один из вещательного радиоприемника, зарегистрированного по потоку А, и один для зарегистрированного им вещательного радиоприемника, или я ошибаюсь? – aeroxr1

+1

Ни ваша, ни моя гарантия не гарантирует, что будет зарегистрирован только один BroadcastReceiver. Если вы хотите это сделать, вам нужно будет использовать 'this.enabled', чтобы указать, что ресивер зарегистрирован. Рассматривали ли вы постоянную регистрацию BroadcastReceiver и разрешаете регистрировать только 0 или 1 слушателя? –

+0

Да, изначально я думал, что так поступаю, но когда приходят статусные значения, важно отменить регистрацию получателя. Как разрешить ресерирование только последнего слушателя? – aeroxr1