← Назад к вопросам

Что делает synchronized с монитором, если применяется к методу?

1.0 Junior🔥 51 комментариев
#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Синхронизированные методы и мониторы в Java/iOS

Когда synchronized применяется к методу в контексте iOS разработки (а точнее в Java/Objective-C, хотя в Swift синтаксис отличается), он работает с монитором объекта, обеспечивая потокобезопасность. В Objective-C это достигается через @synchronized блоки, но принцип аналогичен.

Как это работает

Каждый объект в Java/Objective-C имеет ассоциированный монитор (иногда называемый "встроенной блокировкой" или "mutex"). Когда поток входит в synchronized-метод:

  1. Захват монитора — поток пытается захватить монитор объекта, к которому принадлежит метод
  2. Блокировка доступа — если монитор свободен, поток захватывает его и выполняет метод
  3. Очередь потоков — если монитор занят другим потоком, текущий поток блокируется и ждет освобождения
  4. Освобождение монитора — при выходе из метода (нормальном или через исключение) монитор автоматически освобождается

Пример в Objective-C

// Thread-safe счетчик с synchronized методами
@interface Counter : NSObject
@property (nonatomic) NSInteger value;
- (void)increment;
- (void)decrement;
@end

@implementation Counter

- (void)increment {
    @synchronized(self) {  // Захват монитора объекта self
        self.value = self.value + 1;
    } // Автоматическое освобождение монитора
}

- (void)decrement {
    @synchronized(self) {
        self.value = self.value - 1;
    }
}

@end

Ключевые особенности

Статические synchronized-методы

Для статических методов используется монитор объекта класса (Class object), а не экземпляра:

// Java пример для понимания концепции
public class MyClass {
    public static synchronized void staticMethod() {
        // Использует монитор MyClass.class
    }
}

Область видимости блокировки

Synchronized-метод блокирует весь метод, что может привести к излишней сериализации. Иногда лучше использовать synchronized-блоки с более тонким контролем:

- (void)complexOperation {
    // Несинхронизированная часть
    [self prepareData];
    
    @synchronized(self) {
        // Только критическая секция
        [self updateSharedResource];
    }
    
    // Продолжение несинхронизированной части
}

Рекурсивность

Мониторы в Java/Objective-C рекурсивны — один поток может многократно захватывать один и тот же монитор:

- (void)methodA {
    @synchronized(self) {
        [self methodB]; // Не приводит к дедлоку
    }
}

- (void)methodB {
    @synchronized(self) {
        // Поток уже владеет монитором self
    }
}

Важные нюансы для iOS разработки

Swift альтернативы

В Swift нет прямого аналога @synchronized. Вместо этого используются:

// 1. DispatchQueue с барьером
private let queue = DispatchQueue(label: "com.example.sync", attributes: .concurrent)
private var _value = 0

var value: Int {
    get {
        return queue.sync { _value }
    }
    set {
        queue.async(flags: .barrier) { [weak self] in
            self?._value = newValue
        }
    }
}

// 2. NSLock или os_unfair_lock
private let lock = NSLock()

func synchronizedMethod() {
    lock.lock()
    defer { lock.unlock() }
    // Критическая секция
}

Производительность

@synchronized в Objective-C удобен, но не всегда оптимален по производительности. Более легковесные альтернативы:

  • pthread_mutex_t — POSIX мьютексы
  • os_unfair_lock — более эффективный вариант в iOS 10+
  • NSRecursiveLock — для рекурсивных блокировок

Риски и лучшие практики

  1. Дедлоки — циклические зависимости блокировок

    // Потенциальный дедлок
    @synchronized(objectA) {
        @synchronized(objectB) {
            // ...
        }
    }
    // В другом потоке
    @synchronized(objectB) {
        @synchronized(objectA) {
            // ...
        }
    }
    
  2. Гранулярность — слишком крупные блокировки снижают параллелизм

  3. Альтернативы — рассмотрите actor-модель (Swift 5.5+) для современной конкурентности:

    actor Counter {
        private var value = 0
        
        func increment() {
            value += 1
        }
    }
    

Заключение

synchronized для методов обеспечивает потокобезопасность через монопольный захват монитора объекта, но требует осторожного использования. В iOS-разработке предпочтительнее использовать современные механизмы Swift: DispatchQueue с барьерами, акторы или специализированные примитивы синхронизации, которые обеспечивают лучшую производительность и безопасность при работе с многопоточностью. Ключевое правило — блокировать минимально необходимый участок кода на кратчайшее возможное время.

Что делает synchronized с монитором, если применяется к методу? | PrepBro