2014-07-10 82 views
1

我有一個訪問緩存的Jersey REST服務方法。此方法會跟蹤requestsBeingProcessed,因爲MessageService會定期更新緩存,但只能在沒有處理請求時纔會這樣做。對正在處理的請求數進行遞增和遞減的調用是同步的,以確保線程安全訪問。如何在同步Java線程時避免循環邏輯?

class TeamInfoService { 
    @GET 
    @Path("/{teamId}") 
    @Produces(MediaType.TEXT_PLAIN) 
    public String getTeamInfo(@PathParam("teamId") final int teamId) { 
     MessageService.incrementRequestsBeingProcessed; 
     String team = teamCache.getTeams().get(teamId); 
     MessageService.decrementRequestsBeingProcessed; 
     return team; 
    } 
} 

class MessageService { 
    private static int requestsBeingProcessed = 0; 

    public synchronized static void incrementRequestsBeingProcessed() { 
     requestsBeingProcessed++; 
    } 

    public synchronized static void decrementRequestsBeingProcessed() { 
     requestsBeingProcessed--; 
    } 

    public synchronized static void getRequestsBeingProcessed() { 
     return requestsBeingProcessed; 
    } 
} 

的問題是,MessageService有獲得鎖更新緩存,而只能通過檢查requestsBeingProcessed,只能由一個線程在同一時間訪問更新。

public synchronized static void updateCache(String message) { 
    while(getRequestsBeingProcessed() != 0) { 
     //wait until there are no requests being processed 
    }   
    processMessage(message); 
} 

我有一個雞/蛋這裏的情況:我不能因爲一個鎖需要檢查requestsBeingProcessed鎖更新requestsBeingProcessed。有什麼不同的方式可以解決這個問題嗎?

+1

如果您想直接使用基本併發原語,那麼你應該在looke'Object.wait'和'Object.notify' /'Object.notifyAll'。在'decrementRequestsBeingProcessed'方法中,當你檢測到requestsBeingProcessed達到零時,你可以調用'notify'。這會在'notify'正在執行時解鎖同步監視器 - 檢查Javadoc。 –

回答

2

您需要通知更新線程只要有一個在隊列中沒有項目:

public synchronized static void decrementRequestsBeingProcessed() { 
     if (requestsBeingProcessed > 0) requestsBeingProcessed--;   
     if (requestsBeingProcessed == 0) MessageService.class.notifyAll(); 
} 

public synchronized static void updateCache(String message) { 
    try { 
     while(getRequestsBeingProcessed() != 0) { 
     MessageService.class.wait(); 
     } 
     processMessage(message); 
    } catch (InterruptedException ie) { 
     // devise cancellation strategy here... 
    }  

} 
+0

這就是我正在尋找的東西。謝謝! – woodenToaster

2

我會建議不採用這種方法。正如你所發現的,編寫多線程代碼對於聰明的人來說很難。

您可以嘗試的另一種方法是使用阻塞雙端隊列的producer/consumer排列。內置所需的線程;你不必處理它。

我也會考慮像JCS這樣的緩存解決方案,而不是寫自己的。即使緩存關閉,您的服務也應該可以正常工作。

0

如果您的服務一次只能由一個線程調用,那麼您只需鎖定服務!爲什麼你使用整型變量並鎖定整型變量?

然而,在你的情況下,也許消息隊列或類似的東西是一個優雅的解決方案。

0

你不需要實現它 - 你的策略是對信號量的描述。你可以看到信號量在Wikipedia和Java中的類the oracle documentation中是如何工作的。

+0

我嘗試先使用信號量並遇到同樣的問題。我需要獲取鎖並等待'requestsBeingProcessed'達到0,但另一個線程需要獲取鎖才能更新'requestsBeingProcessed'。 – woodenToaster