2013-07-23 75 views
9

我將全局靜態對象定義爲同步鎖。Android java.lang.IllegalMonitorStateException:對象在wait()之前未被線程鎖定

public static Object ConfirmationSynObj = new Object(); 

以下函數是我寫的,但它拋出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; 
      } 
     } 

有誰知道如何鎖定對象或函數以防止併發?

+5

請遵循Java命名約定。 –

回答

9

wait/notify一個常見的替換是CountDownLatch 。 (從java.util.concurrent很好,但工作的那種Semaphore逆 - 看到答案由湯姆)

你把它初始化爲的步驟所需的量,即已經完成倒計時線程和其他一些地方等待倒計時達到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; 
    } 
} 

但是你寫的代碼也可以簡化爲

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

您啓動第二個線程做一些事情,你在這段時間做的是等待。如果在該任務運行時沒有任何操作,則不要創建額外的線程。結果是一樣的。

如果您嘗試在UI線程之外執行HTTP請求,因爲您獲得了NetworkOnMainThreadExcpeption,則必須以不同的方式執行此操作。雖然Android不會在很長時間內阻止代碼,但它仍然會檢測到您的代碼。例如,使用AsyncTask。

2

您可能正在創建並啓動同步塊中的線程,但當線程進入Config.ConfirmationSynObj.notify();時,您會注意到沒有同步。

您需要在run()中添加一個同步塊。

5

@Kayaman說話正確,據我所知,但是如果我可以虛心地建議:java.util.concurrent可以爲您節省很多時間!我想用的是semaphore

從文檔:「每獲得()阻塞,直到許可證可用,然後把它。」。

但也有其他的選擇 - 我強烈建議儘可能使用這個,因爲你應該避免像你的情況下大量的坑落。

 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() { 

以上線程不上,因此ConfirmationSynObj對象投擲IllegalMonitorStateException

使用一個更多個同步塊內run方法擁有鎖定

  @Override 
      public void run() { 
      synchronized (Config.ConfirmationSynObj) { 
       //this is a http request 
       appSignInfo = getAPKSignature(context, pkinfo.packageName); 
       Config.ConfirmationSynObj.notify(); 
       } 
      } 
相關問題