Рефакторинг блоков синхронизации с сохранением порядка выполнения
У меня есть этот синхронизированный блок в одном из моих классов, основная задача которого - фиксировать метрики вызовов служб. Все переменные с префиксом_
являются переменными класса и являются примитивными длинными. Я хочу провести рефакторинг этого синхронизированного блока, чтобы увеличить пропускную способность, но сохраняя при этом общую точность. У меня есть тестовая установка, которая вызывает этот метод из потоков 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);
}
Хотя пропускная способность действительно увеличивается, как видно из моих тестов, но общая точность метрик, похоже, падает по сравнению с исходным синхронизированным методом. Где-то я мог испортить порядок казней. Может ли кто-нибудь мне с этим помочь?