在同步Java线程时如何避免循环逻辑?

时间:2014-07-10 14:24:41

标签: java multithreading concurrency

我有一个访问缓存的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}}。我应该采用不同的方式解决这个问题吗?

4 个答案:

答案 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中的类。