2016-09-14 3 views
4

Рассмотрим следующий метод:Java синхронизируются метод вокруг значения параметра

public void upsert(int customerId, int somethingElse) { 
    // some code which is prone to race conditions  
} 

Я хочу защитить этот метод от условий гонки, но это может произойти только тогда, когда два потока с одинаковым customerId называют его в то же время , Если я сделаю весь метод synchronized, это уменьшит эффективность и на самом деле не понадобится. Я действительно хочу синхронизировать его вокруг customerId. Возможно ли это как-то с Java? Есть ли встроенные инструменты для этого или мне нужен Map из Integers для использования в качестве замков?

чувствовать себя также свободно советы, если вы думаете, что я делаю что-то здесь :)

Спасибо!

+1

Это, конечно, * чувствует * неправильно. Возможно, вы должны отредактировать свой вопрос, чтобы предоставить более подробную информацию о том, почему * вам нужна синхронизация в первую очередь. –

+3

upsert звучит так, как будто он выполняет некоторую базу данных dml. В этом случае, возможно, вы пытаетесь исправить проблему изоляции транзакций с помощью блокировки? если это так, это будет плохая идея. –

+0

@NathanHughes Я использую старую версию Postgres, где upsert пока недоступен :) –

ответ

11

Концепция, которую вы ищете, называется сегментированная блокировка или полосатая блокировка. Слишком расточительно иметь отдельный замок для каждого клиента (замки вполне тяжеловесные). Вместо этого вы должны указать раздел вашего идентификационного номера клиента в разумное количество разделов, соответствующее желаемой степени параллелизма. Обычно 8-16 будет достаточно, но это зависит от объема работы, которую делает этот метод.

Это описывает простой подход:

private final Object[] locks = new Object[8]; 

synchronized (locks[customerId % locks.length]) { 
    ...implementation... 
}