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



我有一个访问缓存的泽西岛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. 我应该有没有其他方法来解决这个问题?

每当队列中没有项目时,您需要通知更新线程:

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...
    }       
}

我建议不要使用这种方法。 正如你所发现的,即使对于聪明的人来说,编写多线程代码也很困难。

您可以尝试的另一种方法是带有阻塞双面的生产者/消费者安排。 所需的线程是内置的;你不必处理它。

我也会考虑像 JCS 这样的缓存解决方案,而不是编写自己的解决方案。 即使缓存已关闭,您的服务也应正常工作。

如果您的服务一次只能由一个线程调用,那么您只需锁定服务即可!为什么要使用整数变量并锁定整数变量?

但是,在您的情况下,消息队列或类似的东西可能是一个优雅的解决方案。

你不需要实现它 - 你的策略是信号量的描述。您可以在 oracle 文档中查看信号量在维基百科中的工作方式以及 Java 中的类。

最新更新