2013-07-23 7 views
9

Definiuję globalny obiekt statyczny jako blokadę synchronizacji.Android java.lang.IllegalMonitorStateException: obiekt nie jest zablokowany przez wątek przed odczekaj()

public static Object ConfirmationSynObj = new Object(); 

Następująca funkcja jest to, co napisałem, ale rzuca wyjątek IllegalMonitorStateException.

 synchronized (Config.ConfirmationSynObj) { 
      new Thread(new Runnable() { 

       @Override 
       public void run() { 
        //this is a http request 
        appSignInfo = getAPKSignature(context, pkinfo.packageName); 
        Config.ConfirmationSynObj.notify(); 
       } 
      }).start(); 
      try { 
       Config.ConfirmationSynObj.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 

      if (appSignInfo == null) { 
       return ret; 
      } 
     } 

Czy ktoś wie jak zablokować obiektu lub funkcji w celu uniknięcia współbieżności?

+5

Należy przestrzegać konwencji nazewnictwa Java. –

Odpowiedz

9

Częstym zamiennik wait/notify jest CountDownLatch . (Z java.util.concurrent jak dobrze, ale pracuje rodzaju odwrotności Semaphore - patrz odpowiedź przez Tom)

zainicjować go do ilości kroków wymaganych, nici, które wykończono odliczanie i niektóre inne miejsce czeka na odliczanie do osiągnięcia 0.

void doFoo() { 
    final CountDownLatch latch = new CountDownLatch(1); 
    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      //this is a http request 
      appSignInfo = getAPKSignature(context, pkinfo.packageName); 
      latch.countDown(); 
     } 
    }).start(); 
    try { 
     latch.await(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 

    if (appSignInfo == null) { 
     return ret; 
    } 
} 

ale kod napisałeś tam można uprościć do

void doFoo() { 
    return getAPKSignature(context, pkinfo.packageName); 
} 

zacząć drugą nitkę coś zrobić i wszystko co robisz w tym czasie, to czekać. Jeśli nie ma nic do zrobienia podczas wykonywania tego zadania, nie twórz dodatkowego wątku. Wynik jest taki sam.

Jeśli spróbujesz wykonać żądanie HTTP poza wątkiem interfejsu użytkownika, ponieważ otrzymujesz numer NetworkOnMainThreadExcpeption, musisz zrobić to inaczej. Android nie wykryje Twojego kodu jako kodu blokującego, ale wciąż jest. Użyj na przykład AsyncTask.

2

Możliwe, że tworzysz i uruchamiasz wątek w zsynchronizowanym bloku, ale gdy wątek dotrze do Config.ConfirmationSynObj.notify();, zauważysz, że nie ma synchronizacji.

Musisz dodać zsynchronizowany blok wewnątrz funkcji run().

5

@Kayaman mówi poprawnie, o ile mogę powiedzieć, ale jeśli mogę pokornie zasugerować: java.util.concurrent może zaoszczędzić ci dużo czasu!

Co bym tam użył to semaphore.

Z dokumentacji: "Każdy nabywać() blokuje w razie potrzeby, dopóki zezwolenie nie jest dostępne, a następnie bierze go.".

Ale są też inne możliwości - gorąco polecam używanie tego, o ile to możliwe, ponieważ powinieneś unikać wielu upadków, jak w twoim przypadku.

 Semaphore semaphore = new Semaphore(0); 
     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       //this is a http request 
       appSignInfo = getAPKSignature(context, pkinfo.packageName); 
       semaphore.release(); 
      } 
     }).start(); 
     try { 
      semaphore.acquire(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
2
new Thread(new Runnable() { 

      @Override 
      public void run() { 

Przede wątku nie jest posiadanie blokady na ConfirmationSynObj obiekt stąd rzucanie IllegalMonitorStateException

Użyj jednego więcej zsynchronizowany blok wewnątrz run metody

  @Override 
      public void run() { 
      synchronized (Config.ConfirmationSynObj) { 
       //this is a http request 
       appSignInfo = getAPKSignature(context, pkinfo.packageName); 
       Config.ConfirmationSynObj.notify(); 
       } 
      } 
Powiązane problemy