2011-07-18 64 views
0

我有一個客戶端 - 服務器體系結構,服務器有它的客戶端輪流工作,每當客戶端應該工作時傳遞一個參數。客戶端確實使用了參數,當完成時,參數變爲「無效」,不能再用於工作。一旦通過就釋放鎖

我想在運行時避免運行垃圾回收器,所以我避免了對象分配。因此,計劃是服務器將單個參數對象與每個客戶端相關聯,並且每次客戶端被要求完成工作時都會傳遞相同的參數。但是,這會產生這樣一個問題,即該參數必須重新設置爲「有效」,同時還要確保客戶端(可能從最後一次保持對參數的引用)不能開始使用它(說,在不同的線程中)在被要求開始工作之前。

因此所有參數的公共方法都是同步的,並且設置了「有效」狀態,然後在​​塊內部調用客戶端(同步)beginWork。但是這會產生一個問題,即客戶端會不知不覺地持有參數的鎖定,如果客戶端想要將其工作分成多個線程,可能會導致問題。於是我引入了一個單線程ExecutorService,服務器用這個線程將呼叫轉移到beginWork,這確保服務器能夠及時釋放鎖。但是這對我來說似乎是一個糟糕的設計 - 爲什麼這個類需要一個完整的其他線程呢?

所以我的問題是:鑑於我剛剛制定的一切,我是否犯了一些可怕的設計錯誤,導致我過分複雜這個類,還是真的需要這個複雜?

interface Client { 
    public void doWork(Param p); 
} 

interface Param { 
    public boolean isValid(); 
} 

class Server { 
    private final ExecutorService executor = Executors.newSingleThreadExecutor(); 
    private final MyParam[] params; 

    private class MyParam implements Param { 
     boolean isValid; 
     Client client; 
     Runnable task = new Runnable() { 
      @Override 
      public void run() { 
       client.doWork(MyParam.this); 
      } 
     } 

     @Override 
     public synchronized boolean isValid() { 
      return isValid; 
     } 
    } 

    public void runClients() { 
     while (true) { 
      for (MyParam param : params) { 
       synchronized(param) { 
        param.isValid = true; 
        // fork the client so we release the lock promptly (ugly!) 
        executor.execute(param.task); 
       } 

       // ... wait for the client to finish ... 
      } 
     } 
    } 
} 
+0

儘管對象分配速度較慢,但​​鎖定速度可能比對象分配慢得多。將任務添加到執行程序時,至少會創建一個對象。我懷疑你可以減少對象分配,但我必須瞭解更廣泛的問題。 –

+0

@Peter - 鎖定速度可能很慢,但CPU密集度不高。然而,感謝指針 - 看着Java源代碼讓我意識到是的,一個對象被分配。 – Masterofpsi

回答

0

我通過添加顯式ReentrantLockParam接口固定這一點。因此,不要使用同步塊,而是鎖定參數,並讓客戶端解鎖,如果他想。