Оператор synchronized

Хотя создание synchronized методов в ваших классах — простой и эффективный способ достижения синхронизации, все же он работает не во всех случаях. Чтобы понять, почему, рассмотрим следующее. Предположим, что вы хотите синхронизировать доступ к объектам классов, которые не были предназначены для многопоточного доступа. То есть класс не использует методов synchronized. Более того, класс был написан не вами, а независимым разработчиком, и у вас нет доступа к его исходному коду. Значит, вы не можете добавить слово synchronized к объявлению соответствующих методов класса. Как может быть синхронизирован доступ к объектам такого класса? К счастью, существует довольно простое решение этой проблемы: вы просто заключаете вызовы методов этого класса в блок synchronized.

Вот общая форма оператора synchronized:

synchronized(объект) {
// операторы, подлежащие синхронизации
}

Здесь объект — это ссылка на синхронизируемый объект. Блок synchronized гарантирует, что вызов метода-члена объекта произойдет только тогда, когда текущий поток успешно войдет в монитор объекта.

Ниже показана альтернативная версия предыдущего примера с использованием синхронизированного блока внутри метода run ().

// Эта программа использует синхронизированный блок.
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep (1000);
}
catch (InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println("]");
}
}

class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ. String s) {
target = targ;
msg = s;
t = new Thread(this) ;
t.start () ;
}
// синхронизированные вызовы call()
public void run() {
synchronized(target) {
// синхронизированный блок
target.call(msg);
}
}
}
class Synchl {
public static void main(String args[]) {
Callme target = new Callme();
Caller obi = new Caller(target, "Добро пожаловать");
Caller ob2 = new Caller(target, "в синхронизированный");
Caller ob3 = new Caller (target, "мир!");
// wait for threads to end
try {
obi.t.join();
ob2 .t. join () ;
ob3.t.join();
}
catch(InterruptedException e) {
System.out.println("Прервано");
}
}
}

Здесь метод call () не модифицирован словом synchronized. Вместо этого используется оператор synchronized внутри метода run () класса Caller. Это позволяет получить тот же корректный результат, что и предыдущий пример, поскольку каждый поток ожидает окончания выполнения своего предшественника.