Ключевое слово synchronized в Java
Выполняю пример из книги немного мною модифицированный:
public class SynchroRun {
public static AtomicInteger counter = new AtomicInteger(0);
static StringBuilder s = new StringBuilder();
public static void main(String[] args) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (SynchroRun.counter.get() < 3) {
s.append("A");
counter.set(counter.get() + 1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}.start();
Thread.sleep(1);
while (SynchroRun.counter.get() < 6) {
s.append("B");
counter.set(counter.get() + 1);
}
System.out.println("результат: " + s);
}
}
Вывод будет таким: "результат: ABBBBB".
Я не понимаю, почему блок кода из-за слова synchronized не выполняется целиком, я жду "результат: AAABBB".
Зато, если добавить слово synchronized к другому блоку кода, все выполняется так, как я и ожидала:
public class SynchroRun {
public static AtomicInteger counter = new AtomicInteger(0);
static StringBuilder s = new StringBuilder();
public static void main(String[] args) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (SynchroRun.counter.get() < 3) {
s.append("A");
counter.set(counter.get() + 1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}.start();
Thread.sleep(1);
synchronized (s) {
while (SynchroRun.counter.get() < 6) {
s.append("B");
counter.set(counter.get() + 1);
}
}
System.out.println("результат: " + s);
}
}
Вывод: "результат: AAABBB".
Объясните, пожалуйста, что произошло?
Ответы (1 шт):
Синхронизация работает, как блокировка. Первый блок кода заблокировал доступ к объекту s для любого другого кода, которых хочет его изменить или прочитать, и который так же с ним синхронизирован.
В то же время на код, который не синхронизирован с этим объектом, никакие ограничения не накладываются, и он может делать с ним, что хочет.
При желании вы можете заменить структуру вашей программы на аналогичную, используя ReentrantLock.
public class SynchroRun {
private static AtomicInteger counter = new AtomicInteger(0);
private static StringBuilder s = new StringBuilder();
private static Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
lock.lock();
while (counter.get() < 3) {
s.append('A');
counter.incrementAndGet();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}).start();
Thread.sleep(1);
lock.lock();
while (counter.get() < 6) {
s.append('B');
counter.incrementAndGet();
}
lock.unlock();
System.out.println("результат: " + s);
}
}
Здесь всё очень наглядно. Точно так же работает и synchronized.