Атомарное обновление, если текущее значение меньше другого значения - PullRequest
0 голосов
/ 10 мая 2018

Я ищу что-то вроде AtomicInteger или LongAddr, которое будет:

  • Увеличивается, если значение меньше MAX, где MAX - это определенное пользователем значение.
  • Возвращает значение, указывающее, увеличился ли атом.

Использование регистра:

  • У меня есть очередь задач.
  • Одновременно должны выполняться только MAX задачи.
  • Когда новое задание добавляется в очередь, я хочу запустить его, если количество текущих заданий меньше MAX

Причина, по которой я не могу использовать AtomicInteger или LongAddr, заключается в том, что они позволяют сравнивать только определенное значение вместо диапазона значений.

Уточнение : Я не хочу, чтобы решение действительно выполняло задачу. Мой вариант использования включает в себя передачу сетевых запросов в Jetty. Он использует один поток для управления несколькими сетевыми запросами. Любое решение, которое запускает Executor, побеждает эту цель, потому что тогда я получаю один поток на каждый сетевой запрос.

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Использование compareAndSet():

boolean incrementToTheMax(AtomicInteger atomicInt, int max) {
  while (true) {
    int value = atomicInt.get();
    if (value >= max) {
      // The counter has already reached max, so don't increment it.
      return false;
    }
    if (atomicInt.compareAndSet(value, value+1)) {
      // If we reach here, the atomic integer still had the value "value";
      // and so we incremented it.
      return true;
    }
    // If we reach here, some other thread atomically updated the value.
    // Rats! Loop, and try to increment of again.
  }
}
0 голосов
/ 10 мая 2018

Энди Тернер дал отличный ответ , но я считаю это решение более читабельным. По сути, все, что нам нужно, это new Semaphore(MAX) и Semaphore.tryAcquire().

Если вы покопаетесь в исходном коде Semaphore, вы обнаружите, что реализация аналогична ответу Энди.

Вот пример кода:

Semaphore semaphore = new Semaphore(MAX);
// ... much later ...
public void addTask(Runnable task)
{
  if (semaphore.tryAcquire())
    task.run();
  else
    queue.add(task);
}

public void afterTaskComplete(Runnable task)
{
  semaphore.release();
}
...