簡體   English   中英

Java中的線程:如何鎖定對象?

[英]Threading in Java: How to lock an object?

以下函數在其自己的線程中執行:

private void doSendData()
{
    try {

           //writeToFile(); // just a temporary location of a call
           InetAddress serverAddr = InetAddress.getByName(serverAddress);
           serverAddr.wait(60000);
           //Log.d("TCP", "C: Connecting...");
           Socket socket = new Socket(serverAddr, portNumber);
           socket.setSoTimeout(3000);

               try {
                //Log.d("TCP", "C: Sending: '" + message + "'");
                PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                String message = packData();
                out.println(message);
                Log.d("TCP", "C: Sent.");
                Log.d("TCP", "C: Done.");
                connectionAvailable = true;

             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;

               } finally {
                  socket.close();
                  announceNetworkAvailability(connectionAvailable);
                }

         } catch (Exception e) {
              Log.e("TCP", "C: Error", e);
              announceNetworkAvailability(connectionAvailable);
         }
}

當執行到達serverAddr.wait(60000)行時,它會拋出異常:

java.lang.IllegalMonitorStateException: object not locked by thread before wait()

有誰知道如何鎖定對象或函數以防止並發? 我試圖添加一個Lock對象:

private final Lock lock = new ReentrantLock();

和線

boolean locked = lock.tryLock();

在功能的開頭但它沒有用。

為了在對象上調用wait(),您必須在該對象上保持同步鎖(盡管在線程等待時實際釋放了鎖):

synchronized (serverAddr) {
  serverAddr.wait();
}

我不得不承認,在這種情況下你為什么要這樣做會讓我感到困惑......

也許你正在尋找的方法是Thread.sleep(長) 此方法將在恢復之前等待 (如停止執行線程)指定的時間(以毫秒為單位)。

object.wait(long) (這是你正在使用的)做了一些完全不同的事情。 它等待來自另一個線程的另一個對象通知它(即:發送一種喚醒消息),並且最多等待指定的毫秒數。 鑒於您發布的代碼,我非常懷疑這是您真正想要的。

如果Thread.sleep()不是您想要的,那么您應該使用其他海報提到的synchronized塊。

當我看到這種代碼時,我總是畏縮。 幫自己一個忙,看看java.util.concurrent包。

要避免該錯誤消息,請使用synchronized關鍵字:

synchronized(serverAddr){
  serverAddr.wait(60000);
}

以上是正確的。 您可以使用同步的代碼塊。 或者你可以創建他們稱之為互斥的東西。 互斥體實際上可以是任何對象。 很多人只是將Object本身用作互斥體。 然后你可以鎖定互斥鎖。 任何想要訪問的線程都必須等待持有互斥鎖的線程才能釋放它。

Apocalisp也提出了一個建議。 我還建議您查看java.util.concurrent包。

下面的代碼應該工作。

     private final ReentrantLock lock = new ReentrantLock();

     lock.lock();  // block until condition holds
     try {
        serverAddr.wait(60000);
     } finally {
       lock.unlock()
     }
   }

有關更多詳細信息,請參閱此文檔頁面

public void lock()

獲得鎖。

如果鎖沒有被另一個線程保持並獲得鎖定並立即返回,則將鎖定保持計數設置為1。

如果當前線程已經保持鎖定,則保持計數增加1並且該方法立即返回。

如果鎖由另一個線程保持,那么當前線程將被禁用以進行線程調度,並且在獲取鎖定之前處於休眠狀態,此時鎖定保持計數設置為1

請參閱此SE問題以了解lock synchronization的優點:

同步與鎖定

通常,當您在Java中使用多線程程序時,您需要使用synchronized(key-word)來鎖定共享變量,然后在任何時候只需一個線程就可以訪問共享內存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM