← Назад к вопросам
На каком объекте происходит блокировка при выполнении синхронизированного метода
2.0 Middle🔥 211 комментариев
#Многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Синхронизация в Java: объект блокировки
При выполнении синхронизированного метода блокировка происходит на самом объекте (this) для методов экземпляра, или на классе (Class<?> объекте) для статических методов.
Синхронизированный метод экземпляра
Блокировка на самом объекте (this):
public class Counter {
private int count = 0;
// Эквивалентны:
// Способ 1: синхронизированный метод
public synchronized void increment() {
count++; // Блокировка на this
}
// Способ 2: явный блок синхронизации
public void incrementExplicit() {
synchronized (this) { // Явная блокировка на this
count++;
}
}
}
// Использование:
Counter counter = new Counter();
// Два потока конкурируют за одну блокировку (на объекте counter)
Thread t1 = new Thread(() -> counter.increment());
Thread t2 = new Thread(() -> counter.increment());
t1.start();
t2.start();
Статический синхронизированный метод
Блокировка на объекте Class:
public class StaticCounter {
private static int count = 0;
// Блокировка происходит на StaticCounter.class
public static synchronized void increment() {
count++; // Блокировка на StaticCounter.class
}
// Эквивалентно:
public static void incrementExplicit() {
synchronized (StaticCounter.class) { // Явная блокировка на класс
count++;
}
}
}
Визуализация блокировки
┌─────────────────┐
│ Counter obj │
├─────────────────┤
│ count = 0 │
│ (monitor) ┌─┐ │ <- Монитор объекта
│ └─┘ │ Thread может владеть
└─────────────────┘
Если объект синхронизирован:
(monitor) = LOCKED
Различие между методом и статическим методом
public class Demo {
private int instanceValue = 0;
private static int staticValue = 0;
// Каждый ОБЪЕКТ имеет свой монитор
public synchronized void instanceMethod() {
instanceValue++;
}
// КЛАСС имеет монитор (один на всех)
public static synchronized void staticMethod() {
staticValue++;
}
}
// Демонстрация
Demo obj1 = new Demo();
Demo obj2 = new Demo();
// ✅ Разные объекты = разные блокировки!
// Эти потоки НЕ будут ждать друг друга
Thread t1 = new Thread(obj1::instanceMethod);
Thread t2 = new Thread(obj2::instanceMethod);
// ❌ Статические методы = общая блокировка!
// Эти потоки БУДУТ ждать друг друга
Thread t3 = new Thread(Demo::staticMethod);
Thread t4 = new Thread(Demo::staticMethod);
Явная синхронизация для контроля
public class ExplicitLocking {
private int value = 0;
// ❌ Блокировка на this — все методы конкурируют
public synchronized void methodA() {
// медленная операция
}
public synchronized void methodB() {
// медленная операция
}
// ✅ Правильно: разные блокировки = параллелизм
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA_Better() {
synchronized (lockA) {
// медленная операция
}
}
public void methodB_Better() {
synchronized (lockB) {
// медленная операция (параллельна methodA_Better)
}
}
}
Практический пример: счётчик потокобезопасный
public class ThreadSafeCounter {
private int count = 0;
// Блокировка происходит на этом объекте (this)
public synchronized void increment() {
count++; // Критическая секция
}
public synchronized int getCount() {
return count; // Блокировка на this
}
}
// Использование
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadSafeCounter counter = new ThreadSafeCounter();
// 10 потоков, каждый увеличивает счётчик 1000 раз
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment(); // Все конкурируют за монитор
}
});
threads[i].start();
}
// Ждём завершения всех потоков
for (Thread t : threads) {
t.join();
}
System.out.println(counter.getCount()); // 10000 ✅ (не race condition)
}
}
Что такое монитор (Monitor)
Каждый объект в Java имеет встроенный монитор (invisible lock):
public class Object {
// Каждый объект имеет монитор
private Object monitor; // Внутренний монитор
// Можно только захватить/отпустить через synchronized
public void wait() { ... } // Отпустить монитор и ждать
public void notify() { ... } // Пробудить один ожидающий
public void notifyAll() { ... } // Пробудить всех
}
Несколько потоков и одна блокировка
public class MultiThreadExample {
private int value = 0;
public synchronized void criticalSection(String threadName) {
System.out.println(threadName + " захватил монитор");
value++;
try {
Thread.sleep(1000); // Долгая операция
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + " отпускает монитор");
}
}
// Вывод:
// Thread-0 захватил монитор
// Thread-0 отпускает монитор
// Thread-1 захватил монитор
// Thread-1 отпускает монитор
// Thread-2 захватил монитор
// Thread-2 отпускает монитор
// (Поток за потоком, не параллельно!)
Иерархия блокировок
public class LockHierarchy {
private int value = 0;
private final Object monitor = new Object();
// Можно вложить синхронизацию
public void outerLock() {
synchronized (this) { // Блокировка 1
synchronized (monitor) { // Блокировка 2
value++; // Находимся под двумя блокировками
}
}
}
// ⚠️ Опасность: deadlock
public void potentialDeadlock1() {
synchronized (this) {
synchronized (monitor) { // Порядок 1-2
value++;
}
}
}
public void potentialDeadlock2() {
synchronized (monitor) {
synchronized (this) { // Порядок 2-1 - РАЗНЫЙ!
value++; // Может быть deadlock!
}
}
}
}
Современные альтернативы
import java.util.concurrent.locks.ReentrantLock;
public class ModernLocking {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
// Больше контроля, чем synchronized
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // Гарантированно отпустит блокировку
}
}
// Ещё лучше: используй synchronized (Java 5+)
// Или java.util.concurrent.atomic
public void incrementAtomic() {
// AtomicInteger thread-safe без явных блокировок
}
}
Вывод
- ✅ Методы экземпляра: блокировка на this объекте
- ✅ Статические методы: блокировка на Class<?> объекте
- ✅ Явная синхронизация:
synchronized (object)блокирует на object - ✅ Один объект = один монитор (встроенная блокировка)
- ⚠️ Deadlock: правильно упорядочивайте несколько блокировок
- ✅ Альтернативы: ReentrantLock, AtomicInteger, ConcurrentHashMap