, пытаясь улучшить мое понимание проблем параллелизма, я смотрю на следующий сценарий ( Редактировать: Я изменил пример с List на Runtime, что ближе к тому, что я пытаюсь):
public class Example {
private final Object lock = new Object();
private final Runtime runtime = Runtime.getRuntime();
public void add(Object o) {
synchronized (lock) { runtime.exec(program + " -add "+o); }
}
public Object[] getAll() {
synchronized (lock) { return runtime.exec(program + " -list "); }
}
public void remove(Object o) {
synchronized (lock) { runtime.exec(program + " -remove "+o); }
}
}
В настоящее время каждый метод является поточно-безопасным при использовании автономно.Теперь я пытаюсь выяснить, как обработать, где вызывающий класс хочет позвонить:
for (Object o : example.getAll()) {
// problems if multiple threads perform this operation concurrently
example.remove(b);
}
Но, как уже было отмечено, нет никакой гарантии, что состояние будет согласованным между вызовами getAll() и вызовы для удаления ().Если несколько потоков вызовут это, у меня будут проблемы.Итак, мой вопрос - Как я должен позволить разработчику выполнить операцию потокобезопасным способом? В идеале я хотел бы обеспечить безопасность потока таким образом, чтобы разработчику было трудно избежать / пропустить,но в то же время не сложно достичь.До сих пор я могу представить три варианта:
A: Установите блокировку «this», чтобы объект синхронизации был доступен для вызывающего кода, который затем может обернуть блоки кода.Недостаток: Трудно реализовать во время компиляции:
synchronized (example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
B: Поместите объединенный код в класс Example - и получите выгоду от возможности оптимизировать реализацию, как в этом случае.Недостаток: боль при добавлении расширений и потенциальное смешение несвязанной логики:
public class Example {
...
public void removeAll() {
synchronized (lock) { Runtime.exec(program + " -clear"); }
}
}
C: Предоставить класс Closure.Недостаток: избыточный код, который может быть слишком щедрым для блока синхронизации, на самом деле может облегчить взаимоблокировку:
public interface ExampleClosure {
public void execute(Example example);
}
public Class Example {
...
public void execute(ExampleClosure closure) {
synchronized (this) { closure.execute(this); }
}
}
example.execute(new ExampleClosure() {
public void execute(Example example) {
for (Object o : example.getAll()) {
example.remove(b);
}
}
}
);
Есть что-то, чего мне не хватает?Как следует определить область синхронизации, чтобы гарантировать, что код является потокобезопасным?