Рефакторинг блоков синхронизации с сохранением порядка выполнения

У меня есть этот синхронизированный блок в одном из моих классов, основная задача которого - фиксировать метрики вызовов служб. Все переменные с префиксом_являются переменными класса и являются примитивными длинными. Я хочу провести рефакторинг этого синхронизированного блока, чтобы увеличить пропускную способность, но сохраняя при этом общую точность. У меня есть тестовая установка, которая вызывает этот метод из потоков Runnable с помощью службы исполнителя. Я делаю сравнение показателей до и после рефакторинга.

public CallCompletion startCall()
{
  long currentTime;
  Pending pending;

  synchronized (_lock)
  {
    currentTime = _clock.currentTimeMillis();
    _tracker.getStatsWithCurrentTime(currentTime);
    _lastStartTime = currentTime;
    _sumOfOutstandingStartTimes += currentTime;

    _callStartCountTotal++;
    _tracker._callStartCount++;
    if (_callStartsInLastSecondTracker != null)
      _callStartsInLastSecondTracker.addCall();
    _concurrency++;
    if (_concurrency > _tracker._concurrentMax)
    {
      _tracker._concurrentMax = _concurrency;
    }
    pending = checkForPending();
  }
  if (pending != null)
  {
    pending.deliver();
  }
  return new CallCompletionImpl(currentTime);
}

Я пробовал несколько подходов, например:

и) Взлом нескольких замков -

public CallCompletion startCall()
{
  long currentTime;
  Pending pending;

  synchronized (_lock)
  {
    currentTime = _clock.currentTimeMillis();
    _tracker.getStatsWithCurrentTime(currentTime);
    _lastStartTime = currentTime;
    _sumOfOutstandingStartTimes += currentTime;
  }

  synchronization(_lock1) {
    _callStartCountTotal++;
    _tracker._callStartCount++;
    if (_callStartsInLastSecondTracker != null)
      _callStartsInLastSecondTracker.addCall();
    _concurrency++;
    if (_concurrency > _tracker._concurrentMax)
    {
      _tracker._concurrentMax = _concurrency;
    }
    pending = checkForPending();
  }
  if (pending != null)
  {
    pending.deliver();
  }
  return new CallCompletionImpl(currentTime);
}

ii) Использование AtomicLong для _lastStartTime:

public CallCompletion startCall()
{
  long currentTime;
  Pending pending;
  long lastStartTime = _lastStartTime.get();

  if (_callStartsInLastSecondTracker != null) {
    synchronized (_lock) {
      _callStartsInLastSecondTracker.addCall();
    }
  }

  currentTime = _clock.currentTimeMillis();
  if (_lastStartTime.compareAndSet(lastStartTime, currentTime)) {
    _tracker.getStatsWithCurrentTime(currentTime);
    _sumOfOutstandingStartTimes += currentTime;
    _callStartCountTotal++;
    _tracker._callStartCount++;
    _concurrency++;
    if (_concurrency > _tracker._concurrentMax) {
      _tracker._concurrentMax = _concurrency;
    }
  }

  pending = checkForPending();
  if (pending != null)
  {
    pending.deliver();
  }
  return new CallCompletionImpl(currentTime);
}

Хотя пропускная способность действительно увеличивается, как видно из моих тестов, но общая точность метрик, похоже, падает по сравнению с исходным синхронизированным методом. Где-то я мог испортить порядок казней. Может ли кто-нибудь мне с этим помочь?

0 ответов

Другие вопросы по тегам