2015-10-22 43 views
0

請與我裸露我還是很新的線程...簡單的一種方式暫停線程

我有一個小項目,我有2個線程ListenerThreadHeartbeatThread這是內部HeartbeatServer兩個嵌套類。

我有什麼是監聽線程增加了客戶registerClients當有人發送一個請求(剩下的就是出這個問題的範圍)。

我正在尋找一種簡單的方法來暫停HeartbeatThread,當registerClients散列映射中沒有客戶端時。

本來我想它會爲使用if語句在ListenerThread while循環,檢查有多少客戶有,如果客戶端計數小於零ListenerThread稱之爲heartbeatServer.heartbeatThread.wait()和頂部那樣容易當客戶端數量大約爲零時爲heartbeatServer.heartbeatThread.notify()。但是,當我這樣做時,java會拋出一個IllegalMonitorException。在做了一些挖掘之後,我發現這個例外是因爲我沒有在​​塊內調用wait()

因爲我只想去一個方向ListenerThread -> HeartbeatThread並從來沒有任何其他方式我怎麼能做到這一點?在每個線程中使用​​塊還是會更好。如果是這種情況,那麼我需要澄清我正在同步的是什麼。

我發現這個例子;

boolean ready = false; 

// thread 1 
synchronized(lock) { 
    ready = true; 
lock.notifyAll(); 
} 


// thread 2 
synchronized(lock) { 
    while(!ready) 
     lock.wait(); 
} 

這個例子看起來像它會解決我的問題。但由於我是新手,我不確定lock應該是什麼。

能否例如返工或完成適合我的需要,還是有更好的方法來解決我的問題?

我真的不知道什麼代碼將需要表演,所以我可以張貼要求的事情。

UPDATE

我想,我終於想出了一個解決我的問題。 公共類HeartbeatServer {

final Object lock = new Object(); 
volatile Boolean suspended = true; 

//TEST USE ONLY 
volatile int userCount = 0; 

// This is the thread that will send the heartbeats back to the client. 
private class HeartbeatThread implements Runnable { 

    @Override 
    public void run() { 

     HeartbeatServer heartbeatServer = HeartbeatServer.getInstance(); 

     while (true) { 

      synchronized (heartbeatServer.lock) { 

       if(suspended) { 

        try { 

         System.out.println("Suspending heartbeat thread!"); 
         heartbeatServer.lock.wait(); 

        } catch (InterruptedException e) { 

         e.printStackTrace(); 

        } 

       } else { 

        System.out.println("Resuming heartbeat thread!"); 

       } // End if block 

      } // End synchronized block 

      try { 

       Thread.sleep(2000L); 

      } catch (InterruptedException e) { 

       e.printStackTrace(); 

      } 

     } // End while loop 

    } // End run method 

} // End HeartbeatThread 

// This is the thread that will listen for clients connecting to the server. 
private class ListenerThread implements Runnable { 

    // The instance of heartbeatServer should be the first object so we can use it everywhere in the class. 
    HeartbeatServer heartbeatServer = HeartbeatServer.getInstance(); 

    private void suspendHeartbeats() { 

     synchronized (heartbeatServer.lock) { 

      heartbeatServer.suspended = true; 

     } 

    } // End suspendHeartbeats 

    private void resumeHeartbeats() { 

     synchronized (heartbeatServer.lock) { 

      heartbeatServer.suspended = false; 
      heartbeatServer.lock.notify(); 

     } 

    } // End resumeHeartbeats 

    @Override 
    public void run() { 

     while(true) { 

      if(heartbeatServer.userCount < 1) { 

       suspendHeartbeats(); 

      } else { 

       resumeHeartbeats(); 

      } 

     } // End while loop 

    } // End run method 

} // End ListenerThread 

} // End HeartbeatServer 

還有什麼我可以做,以提高我的主題? HeartbeatThread中的一些部分從測試中遺留下來。但我更多地提到用於暫停HeartbeatThread的邏輯。

+1

'lock'可以是任何私人對象。你希望它是私有的,所以其他類不能通過自己同步來干擾你的代碼。實際上,'private static final Object lock = new Object();'通常是一個好習慣。 – VGR

+0

所以'lock'只是兩個線程同步的東西?因此,如果我想暫停'HeartbeatThread',我仍然會像以前那樣調用heartbeatServer.heartbeatThread.wait(),但是隻需在'synchronized'的''synchronized'內爲'lock'指定一個虛擬對象?是正確的嗎? – ianc1215

+1

我建議使用java.util.concurrent.locks.ReentrantLock,因爲它是內置java鎖的更現代和理智的選擇。對於正在學習的人來說,它應該更容易理解 – kan

回答

2

你聽起來像你已經找到了你所需要的核心,它只是信心讓你回來。 wait/notify是Java中相當低級別的基元,並且在使用它們時會出現細微的時序錯誤是很常見的。這就是爲什麼像ReadWriteLock,Semaphore等更高層次的抽象存在。在Java API文檔中有一個示例,演示如何在達到條件(例如空或全)之前阻止here,它們使用ReentrantLock和Condition來表示空/不空。

再回到你對鎖定對象的問題,它只是他們正在呼叫等待/通知侵害的對象。只要它始終是同一個對象,它可以是或多或少的任何對象。

有一個說法,說當使用synchronized/wait/notify時,應該使用私有的最終對象而不是公開的對象。這個說法是,如果鎖對象被暴露,那麼其他代碼本身可能會調用wait/notify/synchronized並導致副作用,這可能會變得棘手以追查。無論如何,螺紋代碼是很難的,所以爭論的目的是減少外部干擾蔓延的機會。這就解釋了你的例子,因爲它遵循這個約定。

+0

我甚至可以說沒有任何人有理由在新編寫的代碼中使用'wait()/ notify()'。 – biziclop

+0

由於我發佈的示例沒有完成,我仍然不確定「鎖定」是什麼。我不想在示例中同步'ready'嗎?除非我不瞭解'synchronized'的用途。 – ianc1215

+0

@ ianc1215準備是一個原始的,它不是一個對象,因此它沒有監視器。因此不能與其同步。 –