Якщо синхронізований метод викликає інший синхронізований метод, чи безпечний він для потоку?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Якщо синхронізований метод викликає інший синхронізований метод, чи безпечний він для потоку?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Відповіді:
Так, коли ви позначаєте методи як synchronized
, тоді ви дійсно робите це:
void method1() {
synchronized (this) {
method2()
}
}
void method2() {
synchronized (this) {
}
}
Коли виклик потоку потрапляє в method2 з method1, тоді він гарантує, що він утримує замок this
, що вже буде, і тоді він може пройти.
Коли потік потрапляє безпосередньо в method1 або method2, тоді він буде блокувати, поки не зможе отримати замок ( this
), а потім увійде.
Як зазначив Джеймс Блек у коментарях, ви повинні бути в курсі того, що ви робите всередині тіла методу.
private final List<T> data = new ArrayList<T>();
public synchronized void method1() {
for (T item : data) {
// ..
}
}
public void method3() {
data.clear();
}
Раптом це не безпечно для потоку, оскільки ви дивитесь на ConcurrentModificationException
своє майбутнє, оскільки method3
воно несинхронізоване, і, отже, може бути викликане Thread A, поки Thread B працює method1
.
method3
показує небезпечні операції з потоковими потоками, але ви знаєте про повторну синхронізацію.
Чи є метод, позначений синхронізованим викликом, іншим безпечним потоком синхронізованого методу.
Загалом, сказати не можна. Це залежить від того, що роблять методи, і від того, які інші методи в тому ж та інших класах.
Однак ми можемо бути впевнені, що виклики method1 і method2 для одного і того ж об'єкта, зроблені різними потоками, не будуть виконуватися одночасно. Залежно від того, що роблять методи, цього може бути достатньо, щоб сказати, що клас є безпечним для потоків щодо цих методів.
З веб-сайту підручників Java http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Неможливо чергувати два виклики синхронізованих методів на одному об'єкті. Коли один потік виконує синхронізований метод для об'єкта, усі інші потоки, що викликають синхронізовані методи для того самого блоку об'єктів (призупинення виконання), поки перший потік не буде виконаний з об'єктом.
коли синхронізований метод виходить, він автоматично встановлює взаємозв'язок "до-до" з будь-яким подальшим викликом синхронізованого методу для того самого об'єкта. Це гарантує, що зміни стану об'єкта видно для всіх потоків
Отже, Java забезпечить, що якщо 2 потоки виконують один і той же метод, методи виконуватимуться не одночасно, а один за одним.
Але ви повинні знати про проблему Liveness, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
А також чи ви постійно блокуєтесь, вкажіть у коді, який ви використовували це , який блокує весь об'єкт, якщо ваш об'єкт потребує лише доступу синхронізації до однієї змінної, вам слід просто заблокувати цю змінну.
synchronized (this.someVar)
, що дивитесь на об’єкт, посилання на який зберігається someVar
. Розрізнення дуже важливо.