Как я могу избежать круговой логики при синхронизации потоков Java?

1

У меня есть метод службы 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
    Если вы хотите напрямую использовать базовые примитивы параллелизма, тогда вам стоит поискать в Object.wait и Object.notify / Object.notifyAll . В decrementRequestsBeingProcessed , когда вы обнаруживаете, что requestBeingProcessed достигает нуля, вы можете вызвать notify . Это разблокирует синхронизированный монитор во время выполнения notify - проверьте Javadoc.
Теги:
multithreading
concurrency

4 ответа

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
    Это то, что я искал. Спасибо!
2

Я бы посоветовал против такого подхода. Поскольку вы обнаруживаете, писать многопоточный код трудно даже для умных людей.

Другой подход, который вы могли бы попробовать, - это соглашение производителя/потребителя с блокирующим детексом. Встраивается требуемая резьба; вам не придется иметь дело с этим.

Я бы также рассмотрел такое кэширующее решение, как JCS, вместо того, чтобы писать ваши собственные. Ваш сервис должен работать, даже если кеширование отключено.

0

Если ваша услуга может быть вызвана только одним потоком за раз, то вы просто ЗАБРОНИРУЕТ СЕРВИС! Почему вы используете целочисленную переменную и блокируете целочисленную переменную?

Однако, в вашем случае, может быть, очередь сообщений или что-то в этом роде является изящным решением.

0

Вам не нужно его реализовывать - ваша тактика - это описание семафора. Вы можете видеть, как семафоры работают в Википедии и классе на Java в документации оракула.

  • 0
    Сначала я попытался использовать семафор и столкнулся с той же проблемой. Мне нужно получить блокировку и подождать, пока requestsBeingProcessed достигнет 0, но другой поток должен получить блокировку, чтобы обновить requestsBeingProcessed .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню