synchronized
Разрешает выполнять блок кода только одному потоку за раз.
Доступно с: Java 1.0
Синтаксис
synchronized void method() { ... }
synchronized (lock) { ... }Примеры
Безопасный счётчик:
class Counter {
private int value;
synchronized void increment() {
value++;
}
synchronized int get() {
return value;
}
}
void main() throws InterruptedException {
var counter = new Counter();
Runnable task = () -> { for (int i = 0; i < 10_000; i++) counter.increment(); };
Thread a = new Thread(task), b = new Thread(task);
a.start(); b.start();
a.join(); b.join();
IO.println(counter.get());
}Результат:
20000Блок с отдельным объектом-замком:
void main() throws InterruptedException {
Object lock = new Object();
List<Integer> shared = new ArrayList<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
synchronized (lock) {
shared.add(i);
}
}
};
Thread a = new Thread(task), b = new Thread(task);
a.start(); b.start();
a.join(); b.join();
IO.println(shared.size());
}Результат:
2000Примечания
Без synchronized операция value++ из двух потоков теряет обновления, и результат обычно меньше 20000. Синхронизированный метод экземпляра блокирует this, статический — класс. Внутри блока изменения, сделанные другим потоком до выхода из его блока, гарантированно видны.
См. также
- ReentrantLock — Явная блокировка — гибкая замена `synchronized`.
- AtomicInteger — Целое число, которое можно безопасно менять из нескольких потоков без блокировок.
- volatile — Помечает поле, изменения которого сразу видны всем потокам.
Вопросы и ответы по теме
В учебнике
- Синхронизация — Гонка данных в Java и как её избежать — synchronized-методы и блоки, атомарные классы AtomicInteger, ReentrantLock и общий объект блокировки.