Выполняются ли одновременно два синхронизированных метода
У меня есть 4 метода (m1
, m2
, m3
и m4
) в классе. Метод m1
, m2
и m3
- это методы synchronized
. Кроме того, у меня есть 4 потока t1
, t2
, t3
и t4
соответственно.
Если t1
получить доступ к методу m1
(синхронный метод), может ли метод t2
использовать поток m2
(синхронный метод) одновременно? Если бы не состояние t2?
Ответы
Ответ 1
Если t1 получить доступ к методу m1 (синхронный метод), может ли метод t2 потокового доступа m2 (синхронный метод) одновременно?
Ключевое слово synchronized
применяется на уровне объекта, и только один поток может удерживать блокировку объекта. Поэтому, пока вы говорите об одном и том же объекте, no, t2
будет ждать t1
, чтобы освободить блокировку, полученную при вводе m1
.
Однако поток может освободить блокировку, не возвращаясь из метода, вызывая Object.wait()
.
Если нет, каково будет состояние t2?
Он будет сидеть и ждать t1
, чтобы освободить блокировку (возврат из метода или вызов Object.wait()
). В частности, он будет находиться в состоянии BLOCKED
.
Состояние потока для потока, заблокированного в ожидании блокировки монитора. Нить в заблокированном состоянии ожидает блокировки монитора для ввода синхронизированного блока/метода или повторного входа в синхронизированный блок/метод после вызова Object.wait
.
Пример кода:
public class Test {
public synchronized void m1() {
try { Thread.sleep(2000); }
catch (InterruptedException ie) {}
}
public synchronized void m2() {
try { Thread.sleep(2000); }
catch (InterruptedException ie) {}
}
public static void main(String[] args) throws InterruptedException {
final Test t = new Test();
Thread t1 = new Thread() { public void run() { t.m1(); } };
Thread t2 = new Thread() { public void run() { t.m2(); } };
t1.start();
Thread.sleep(500);
t2.start();
Thread.sleep(500);
System.out.println(t2.getState());
}
}
Вывод:
BLOCKED
Ответ 2
Если методы синхронизируются на одном мониторе, они не могут выполняться одновременно в разных потоках. Когда второй поток приходит к записи монитора (в этом случае запускается синхронизированный метод), он будет блокироваться до тех пор, пока первый поток не освободит монитор.
Фактическое состояние заблокированного потока в этом случае, как сообщается jconsole, будет чем-то вроде java.lang.Thread.State: WAITING (on object monitor)
Предполагая, что все методы являются обычными методами экземпляра, тогда они будут использовать один и тот же монитор при вызове на одном и том же объекте. То есть, если у вас есть что-то вроде:
// Thread 1
A a1 = new A();
a1.m1();
// Thread 2
A a2 = new A();
a2.m2()
то в этом случае второй поток сможет вызвать метод, потому что он пытается получить неявный монитор объекта a2
, который не заблокирован потоком 1. Но если поток 2 попытался вызвать a1.m2()
, то он будет блокироваться, пока поток 1 не завершит выполнение m1()
.
Если у вас есть статические методы, они получают явный монитор самого класса (A.class
в моем случае с гипотетическим именованием), поэтому он не будет заблокирован вызовами метода экземпляра.
Ответ 3
Нет, не мог. Единственное, что существует для synchronized
: разные потоки не могут делать эти вещи одновременно (вам не нужно защищать один поток от них одновременно, потому что один поток не может ничего делать параллельно. ) Состояние ожидающего потока "ждет блокировки". (С достаточно современной JVM вы можете фактически отобразить это состояние на консоли, если вы спросите правильно.)
Ответ 4
Если t1 получить доступ к методу m1 (синхронный метод), может ли метод t2-потока доступа m2 (синхронный метод) одновременно?
Нет. Thread t2 будет ждать, пока Thread t1 освободит блокировку.
В том же примере t2 может получить доступ к методу m4, который не синхронизирован.
Замки в synchronized Методы
Каждый объект имеет связанный с ним встроенный замок. По соглашению поток, который нуждается в эксклюзивном и последовательном доступе к полям объекта, должен получить внутреннюю блокировку объекта перед доступом к ним, а затем освободить внутреннюю блокировку, когда она будет выполнена с ними.
Когда поток вызывает синхронизированный метод, он автоматически получает внутреннюю блокировку для этого объекта метода и освобождает его при возврате метода. Блокировка блокировки происходит даже в том случае, если возврат был вызван неперехваченным исключением
Возвращаясь к вашему второму запросу:
Если нет, то каково было бы состояние t2?
Поток t2 находится в заблокированном состоянии и ожидает, пока поток t1 освободит блокировку.
Из java документация:
метод synchronized
имеет два эффекта.
Во-первых, невозможно, чтобы две вызовы синхронизированных методов на одном объекте чередовали. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же объекта (приостанавливать выполнение) до тех пор, пока первый поток не будет выполнен с объектом.
Во-вторых, когда синхронизированный метод завершается, он автоматически устанавливает связь между событиями и последующим вызовом синхронизированного метода для одного и того же объекта. Это гарантирует, что изменения состояния объекта видны для всего потока