Synchronized: какво е това, принцип на действие и използване в Java

Автор: IT Sectr Публикувано: 2026-03-19 Време за четене: 8 мин

Synchronized е вграден механизъм за синхронизация в езика Java, осигуряващ ексклузивен достъп до критични секции от кода. Според Oracle, 2024, модификаторът synchronized гарантира, че само една нишка може да изпълнява маркирания метод или блок в даден момент. Този механизъм се основава на монитори — фундаментална концепция на операционните системи, осигуряваща коректната работа на многонишкови приложения на всички нива на сложност.

Основни точки

  • Synchronized — ключова дума Java за безопасен достъп до данни.
  • Монитор на обект — вътрешният механизъм, на който се основава синхронизацията.
  • Synchronized метод блокира целия метод на ниво инстанция или клас.
  • Synchronized блок позволява синхронизация само на част от кода.
  • Deadlock — един от основните проблеми при вложена синхронизация.

Какво е synchronized?

Synchronized е ключова дума в Java, която гарантира, че само една нишка едновременно изпълнява защитената част от кода, предотвратявайки повреда на данни при паралелен достъп. Тя се появи в първата версия на Java и остава най-простият начин за осигуряване на нишкова безопасност за разработчици на всички нива.

Определение и роля в Java

Модификаторът synchronized решава две задачи: взаимно изключване (mutual exclusion) и видимост на промените (visibility). Когато нишка напусне synchronized блок, всички промени са гарантирано видими за други нишки, влизащи в блока, синхронизиран на същия обект.

Synchronized може да се приложи към целия метод или към произволен блок код с посочване на обект-монитор. И в двата случая JVM вмъква инструкциите monitorenter и monitorexit на ниво байткод.

Причини за появата

В многонишкови приложения без синхронизация възниква състояние на надпревара (race condition) — когато две нишки едновременно променят едни и същи данни, което води до непредвидими резултати. Synchronized стана първият и основен инструмент на Java за борба с този проблем, предоставяйки прост декларативен синтаксис, достъпен за всеки разработчик.

Как работи synchronized?

Механизмът synchronized се основава на концепцията за монитор — високо ниво на примитив за синхронизация, вграден във всеки Java обект. Мониторът се свързва с обекта при първото използване на synchronized блок върху него.

Монитор на обект

Всеки обект в Java има асоцииран монитор. Когато нишка влезе в synchronized блок, тя завзема монитора на обекта. Ако мониторът вече е зает от друга нишка, нишката се блокира до освобождаването. В байткода на това съответства двойката инструкции monitorenter и monitorexit.

Състояния на заключване (biased locking)

JVM оптимизира synchronized чрез няколко нива: biased locking (пристрастно заключване) за еднонишков достъп, lightweight locking (леко заключване) при слаба конкуренция и heavyweight locking (тежко заключване) при интензивна конкуренция с участие на ОС. Тези нива повишават производителността без промяна на кода.

java
class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

Правилото happens-before

Synchronized установява релация happens-before: всички действия в нишка преди излизане от synchronized блок са видими за друга нишка след влизане в блок, синхронизиран на същия обект. Това гарантира не само взаимно изключване, но и консистентност на данните за всички нишки.

Synchronized метод срещу блок

Java предлага два начина за прилагане на synchronized: на ниво метод и на ниво блок. Изборът между тях влияе на производителността и грануларността на синхронизацията.

Synchronized метод

Маркирайки метод с модификатора synchronized, вие автоматично го синхронизирате на текущата инстанция (за обикновен метод) или на обекта Class (за статичен метод). Това е най-простият начин за осигуряване на взаимно изключване, но често е излишен, ако критичната секция съставлява само малка част от метода, а останалият код не изисква синхронизация.

Synchronized блок

Synchronized блокът дава прецизен контрол: вие посочвате обект-монитор и синхронизирате само необходимата част от кода, оставяйки останалата част от метода извън заключването. Това минимизира времето на задържане на монитора и повишава общата производителност на приложението в многонишкова среда, тъй като други нишки могат паралелно да изпълняват несвързан код, без да чакат освобождаване на монитора.

java
class DataProcessor {
    private final Object lock = new Object();

    public void process() {
        // код извън критичната секция - без синхронизация
        prepareData()

        synchronized (lock) {
            // само този блок е защитен
            updateSharedState()
        }

        // продължение без заключване
        cleanup()
    }
}
КритерийSynchronized методSynchronized блок
Мониторthis (инстанция) или Classвсеки обект
Грануларностцелият методсамо необходимият код
Четимоствисокасредна
Производителностпо-ниска при голям методпо-висока при малка критична секция

Synchronized в Android

В разработката за Android, synchronized се използва широко за защита на SharedPreferences, достъп до база данни и UI компоненти. Въпреки това, използването му на основната нишка категорично не се препоръчва поради риск от замръзване на интерфейса.

Използване с SharedPreferences

SharedPreferences в Android осигурява основна нишкова безопасност, но при редактиране от множество нишки чрез Editor може да се наложи външна синхронизация. Synchronized блок с отделен обект за заключване гарантира консистентност на промените.

kotlin
class PreferencesManager(private val prefs: SharedPreferences) {
    private val lock = Any()

    fun writeToken(token: String) {
        synchronized (lock) {
            prefs.edit()
                .putString("auth_token", token)
                .apply()
        }
    }
}

Ограничения в Android приложения

Основното ограничение на synchronized в Android — блокиране на нишка. За разлика от корутините с Mutex, synchronized блокира цялата системна нишка. На основната нишка това причинява ANR. В съвременната Android разработка се препоръчва замяна на synchronized с корутини (suspend Mutex) или атомарни типове (AtomicInteger).

Алтернативи на synchronized

Съвременните Java и Kotlin предлагат няколко алтернативи на synchronized, всяка от които решава същите задачи с по-малко ограничения или по-добра производителност.

Lock от java.util.concurrent

Интерфейсът Lock с реализации ReentrantLock и ReadWriteLock предоставя таймаути, прекъсваемо изчакване и множество опашки Condition. Той е по-гъвкав от synchronized, но изисква изрично освобождаване в finally, което увеличава риска от грешка при забравен unlock.

Атомарни класове

Класовете AtomicInteger, AtomicLong, AtomicReference и други използват Lock-Free алгоритми, базирани на CAS (Compare-And-Swap). Те са значително по-бързи от synchronized в сценарии с умерена конкуренция, тъй като не блокират нишки, а изпълняват оптимистични повторни опити и не изискват превключване на контекста от ядрото на ОС.

ThreadLocal и безопасност на нишките

ThreadLocal предоставя алтернативен подход: всяка променлива ThreadLocal е изолирана в рамките на една нишка и не изисква синхронизация за четене и писане. Това напълно елиминира необходимостта от synchronized за данни, които не трябва да се споделят между нишки. ThreadLocal се използва активно в рамки (Spring, Hibernate) за съхранение на контекст на транзакции и сесии.

Корутини и compose подход

В Kotlin проекти за Android, алтернативата на synchronized е Mutex от kotlinx.coroutines. Той не блокира нишката на операционната система, а спира корутината до освобождаване на заключването — това позволява ефективно използване на нишки от пула и избягване на ANR при дълго чакане за освобождаване на ресурс.

kotlin
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

val mutex = Mutex()
var counter = 0

suspend fun safeIncrement() {
    mutex.withLock {
        counter++
    }
}

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

Производителността на synchronized се е променила значително в последните версии на Java. Преди се смяташе за „тежък„ механизъм, но съвременните JVM елиминираха повечето допълнителни разходи благодарение на напреднали оптимизации на JIT компилатора. Нека разгледаме подробно как виртуалната машина ускорява синхронизирания код по време на изпълнение.

Biased Locking и Lock Coarsening

JIT компилаторът на JVM прилага няколко оптимизации: biased locking елиминира синхронизацията, ако заключването винаги се завзема от една нишка; lock coarsening обединява съседни synchronized блокове в един; lock elimination премахва синхронизацията, ако обектът е достъпен само за една нишка. Тези оптимизации правят synchronized практически безплатен при ниска конкуренция.

Измерване на конкуренция и избор на оптимизация

JVM определя нивото на конкуренция за всеки обект: при липса на конкуренция се активира biased locking, при поява на втора нишка заключването преминава в lightweight режим с spin-изчакване и едва при продължително чакане — в heavyweight със системен мютекс. Тази ескалация става автоматично и разработчикът не трябва ръчно да избира стратегия.

Сравнение с Lock и атомарни класове

В съвременни бенчмаркове (Java 17+) synchronized показва производителност, сравнима с ReentrantLock при ниска и умерена конкуренция. При висока конкуренция Lock може да има предимство благодарение на по-ефективна опашка за изчакване с поддръжка на таймаути и прекъсвания. За високонатоварени системи, където конкуренцията е постоянна, ReentrantLock в fair режим дава по-предвидимо поведение.

Атомарните класове (AtomicInteger, AtomicReference) остават най-бързи за прости броячи и флагове благодарение на Lock-Free имплементация на CAS. Те изобщо не блокират нишки — при конфликт операцията просто се повтаря в цикъл. Това дава 3-5 пъти повишаване на производителността в сравнение със synchronized при операции за увеличаване на брояч на 4-8 нишки.

Често задавани въпроси

Каква е разликата между synchronized и volatile?

Synchronized осигурява както взаимно изключване, така и видимост. Volatile гарантира само видимост на промените — записът в volatile променлива е видим за всички нишки, но не предотвратява едновременната промяна, т.е. не защитава от състояние на надпревара.

Може ли synchronized да причини deadlock?

Да, deadlock е възможен при вложена синхронизация с различен ред на мониторите. Например една нишка извиква synchronized(a) { synchronized(b) }, а друга — synchronized(b) { synchronized(a) }. Избягвайте вложени synchronized блокове или фиксирайте единен ред на мониторите.

Какво е монитор в Java?

Монитор е механизъм за синхронизация, свързан с всеки Java обект. Той гарантира, че само една нишка изпълнява synchronized код на дадения обект. Мониторът включва заключване, опашка за изчакване и набор от нишки, чакащи уведомление чрез wait/notify.

По-бърз ли е Lock от synchronized?

В съвременните версии на Java (17+) synchronized не отстъпва на Lock по производителност благодарение на JIT оптимизациите (biased locking, lock coarsening). Lock се предпочита не заради скорост, а заради допълнителни възможности: таймаути, прекъсваемо изчакване и множество Condition.

Как synchronized работи със статични методи?

Статичният synchronized метод използва монитора на обекта Class на дадения клас, а не на инстанцията. Това означава, че синхронизацията обхваща всички инстанции на класа. Нестатичните и статичните synchronized методи използват различни монитори и не блокират един друг.

Резюме

  • Synchronized — вграден механизъм за синхронизация в Java, основан на монитори.
  • Монитор на обект — вътрешна структура на JVM, осигуряваща взаимно изключване.
  • Методите wait/notify се използват само вътре в synchronized блокове или методи.
  • Synchronized блок е за предпочитане пред метод поради по-фина грануларност на синхронизация.
  • Happens-before гарантира видимост на промените между нишки при синхронизация на един и същ обект.
  • Deadlock — основният риск при вложена синхронизация с различен ред на мониторите.
  • Алтернативи — Lock, атомарни класове и корутини с suspending Mutex.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също