Скажем, мы создаем поток, который запускает синхронизированный метод. Этот метод пытается выполнить take()
из пустой очереди блокировки. Теперь позвольте отдельному потоку затем попытаться установить put()
и элемент в очередь блокировки при синхронизации на одном и том же объекте.Тупик, вызванный методами блокировки
Это приводит в тупик:
- Первый поток не освободит блокировку до тех пор, пока элемент добавляется в очередь.
- Вторая нить не может добавить элемент до тех пор, пока замок не станет свободным для его приобретения.
Если два действия должны быть атомарными и выполняться на отдельных потоках, как это можно достичь, не вызывая тупика?
Я понимаю, что take()
и put()
являются потокобезопасными. Мой вопрос заключается в том, когда они используются как часть более крупных действий, которые должны быть атомарными.
Пример:
import java.util.concurrent.*;
public class DeadlockTest {
String input = "Nothing added yet!";
LinkedBlockingQueue<String> buffer = new LinkedBlockingQueue<>();
public synchronized String getFromBuffer() {
System.out.println("Trying to get input from buffer.");
try {
input = buffer.take();
} catch (InterruptedException ex) {}
System.out.println("Got:" + input + "\n");
return input;
}
public static void main(String[] args) throws InterruptedException {
DeadlockTest dl = new DeadlockTest();
new Thread(() -> {
dl.getFromBuffer();
}).start();
// Give new thread time to run.
Thread.sleep(500);
synchronized (dl) {
String message = "Hello, world!";
System.out.println("Adding: " + message);
dl.buffer.put(message);
System.out.println("Added!\n");
System.out.println("Message: " + dl.input);
}
}
}
Ну, да, так что возьмите/поп/что угодно, чтобы освободить замок, даже если очередь пуста. –
Обычно вы используете дополнительный поток для выполнения блокировки, а затем читаете результаты с помощью какого-либо цикла событий. –
@MartinJames Объект блокировки, который 'take()' и 'put()' приобретает и выпускает, не является тем же, который использует синхронизированный метод. У меня нет доступа к внутренней блокировке для блокирующей очереди.Если бы я это сделал, я мог бы использовать его в качестве аргумента для синхронизированного блока вместо того, чтобы синхронизировать этот метод. – nolanar