Есть переменные экземпляра, переменные класса, локальные переменные, литералы, ссылочные типы, примитивные типы.
К чему из перечисленного (потокам) необходимо координировать многопоточный доступ (использовать через синхронизированные блок/метод)?
Есть переменные экземпляра, переменные класса, локальные переменные, литералы, ссылочные типы, примитивные типы.
Вы намешали все в кучу: есть несколько видов переменных (экземпляра, класса, локальные), каждая из которых может быть разного типа - примитив, ссылка на объект. Работа с литералами (объектами типа String) проходит так же как и с другими ссылочными типами.
При работе в многопоточном режиме необходимо координировать доступ к разделяемым ресурсам - очевидно, что локальные переменные таковыми не являются и их экземпляры создаются для каждого потока.
Необходимость синхронизации при работе с переменными класса и переменными экземпляра зависит от того, что вы с ними делаете. Например, переменные класса - это обычно какие-то константы (static final
) - примитивы, либо immutable объекты и, соответственно, их значение не изменяется во время работы всей программы и нет необходимости синхронизировать доступ к ним.
Если проводятся какие-либо неатомарные модификации (неважно над переменной класса или экземпляра), то необходима ручная синхронизация (либо использование специальных классов для многопоточной работы - различные Atomic-и, Concurrent-коллекции и пр.). Рассмотрим на простом примере:
private volatile int i = 0; // volatile, чтобы переменные не хранились в кэше и значения были одинаковы во всех потоках
public int incrementAndGet(){
i = i + 1;
return i;
}
Метод incrementAndGet
должен увеличить значение i
на 1 и вернуть новое значение. Однако, если этот метод будет вызван одновременно в 2 потоках, то результат метода непредсказуем: в каждом из потоков, он может вернуть как 1, так и 2. Это происходит из-за того, что операция инкремента неатомарна (сперва считывается текущее значение, затем к нему добавляется 1 и затем происходит запись - и на любом из этих шагов исполнения в одном потоке может "вклиниться" другой поток).
Для того, чтобы разрешить эту проблему метод должен быть synchronized или использовать специально созданный класс AtomicInteger
в пакете java.util.concurrent.atomic
.
Вы наверное неправильно понимаете суть синхронизированых блоков. Почитайте про состояние гонки (Race Conditional). Если коротко и на примере, то эта ситуация, когда один поток читает объект, уже прочитал полобъекта и тут бац, система переключила на другой поток, который начал писать в этот ообъект, дописал до конца, и тут снова переключил на первый поток, который дочитывает вторую половину уже измененного объекта. В итоге объект читается криво (пол старого состояния, пол нового).
Собственно и ответ на ваш вопрос - синхронизировать нужно только тогда, когда возможно такое изменение. А это любые мутабельные объекты (у иммутабельных объектов иммунитет против этого - если объект нельзя изменить, значит и состояния гонки не может быть, ведь его нельзя писать, только читать), в которых будет происходить изменение (если объект никто не меняет, то есть он фактически иммутабельный - поменять его можно, но никто этого не делает, то опять нет ситуации гонки) в разных потоках (если вы не планируете работать с объектом из разных потоков, то и нет смысла думать о многопоточности).
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Углубляю познания о джавеНаткнулся на статью о типах ссылок
В моём приложении на андроид я использую несколько звуков с помощью класса soundpool,теперь я хочу реализовать функцию записи звука внутри своего...
Есть класс , который выполняет деление столбиком и результат отображает графически выводом в консольКак протестировать такой метод?