我有一個客戶端 - 服務器體系結構,服務器有它的客戶端輪流工作,每當客戶端應該工作時傳遞一個參數。客戶端確實使用了參數,當完成時,參數變爲「無效」,不能再用於工作。一旦通過就釋放鎖
我想在運行時避免運行垃圾回收器,所以我避免了對象分配。因此,計劃是服務器將單個參數對象與每個客戶端相關聯,並且每次客戶端被要求完成工作時都會傳遞相同的參數。但是,這會產生這樣一個問題,即該參數必須重新設置爲「有效」,同時還要確保客戶端(可能從最後一次保持對參數的引用)不能開始使用它(說,在不同的線程中)在被要求開始工作之前。
因此所有參數的公共方法都是同步的,並且設置了「有效」狀態,然後在塊內部調用客戶端(同步)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 ...
}
}
}
}
儘管對象分配速度較慢,但鎖定速度可能比對象分配慢得多。將任務添加到執行程序時,至少會創建一個對象。我懷疑你可以減少對象分配,但我必須瞭解更廣泛的問題。 –
@Peter - 鎖定速度可能很慢,但CPU密集度不高。然而,感謝指針 - 看着Java源代碼讓我意識到是的,一個對象被分配。 – Masterofpsi