我有一个访问缓存的Jersey REST服务方法。此方法会跟踪requestsBeingProcessed
,因为MessageService
会定期更新缓存,但只有在没有处理请求时才会这样做。增加和减少正在处理的请求数的调用将被同步,以确保线程安全访问。
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}}。我应该采用不同的方式解决这个问题吗?
答案 0 :(得分:2)
我会反对这种做法。正如您所发现的那样,即使是聪明人也很难编写多线程代码。
你可以尝试的另一种方法是producer/consumer安排阻塞双端队列。内置所需的线程;你不必处理它。
我还会考虑像JCS这样的缓存解决方案而不是编写自己的缓存解决方案。即使关闭了缓存,您的服务也应该有效。
答案 1 :(得分: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...
}
}
答案 2 :(得分:0)
如果您的服务一次只能由一个线程调用,那么您只需锁定服务即可!为什么使用整数变量并锁定整数变量?
但是,在您的情况下,可能是一个消息队列或类似的东西是一个优雅的解决方案。
答案 3 :(得分:0)
您不需要实现它 - 您的策略是信号量的描述。您可以在Wikipedia中查看信号量的工作方式以及the oracle documentation中的Java中的类。