#java #multithreading #spring #phaser
#java #многопоточность #весна #phaser
Вопрос:
У меня есть spring @Controller, который имеет сопоставление запросов. Когда на него отправляются запросы, он создает отложенный результат и запускает метод в классе делегатора.
В контроллере:
@ResponseBody
@RequestMapping(MenuModelCodes.MENU_NAME)
DeferredResult<HttpEntity<?>> getModelCodesWithClass(String target) {
final DeferredResult<HttpEntity<?>> deferredResult = getNewDeferredResult();
delegator.doStuff(target);
return deferredResu<
}
Метод doStuff в делегаторе имеет аннотацию @Async, поэтому он выполняется в другом потоке.
В этом потоке создается новый Phaser для отслеживания дочерних потоков, которые он создаст.
Сам поток делегатора регистрируется в phaser и запускает вызов метода в «AnotherClass», который также имеет аннотацию @Async. Т.Е. делегатор теперь порождает дочерние элементы.
Делегатор:
public class Delegator {
@Async
public Object doStuff(String requestURI) {
Phaser phaser = new Phaser();
phaser.register();
Object result = anotherClass.createThreadDoWork(phaser);
phaser.arriveAndDeregister();
//Wait until phaser is completed
while (!phaser.isTerminated()) {}
return resu<
}
}
Каждый дочерний порожденный поток, созданный вызовом в делегаторе createThreadDoWork здесь, регистрируется в фазере, выполняет некоторую работу, а затем прибывает и отменяет регистрацию.
Другой класс:
public class AnotherClass {
@Async
public void createThreadDoWork(Phaser phaser) throws Throwable {
phaser.register();
//some kind of logic / rest call etc.
phaser.arriveAndDeregister();
}
}
Когда все дочерние потоки завершатся, делегатор, который находится в этом фрагменте кода:
while (!phaser.isTerminated()) {}
Будет продолжено, установите его отложенный результат, и поток делегатора завершится.
Итак, вот вопрос (ы):
Мне нужен фазер для каждого запроса — т. Е. Я создаю новый Phaser() каждый раз, когда запрос создает новый поток делегатора.
Если я получаю 5 запросов к своему контроллеру, каждый из них порождает поток делегатора, каждый делегатор создает новый фазер и передает его своим дочерним элементам. Однако, как только один из потоков завершает свою обработку и его конкретный экземпляр Phaser завершается, другие потоки делегатора продолжают и возвращаются, не выполнив свои задачи.
Можно ли использовать фазеры таким образом? Я делаю что-то не так? Я подумал, что это было бы полезным способом отслеживать завершение дочерних потоков и ждать их завершения?
Спасибо.
Ответ №1:
Можно ли использовать фазеры таким образом?
Да, его можно использовать таким образом, и обычно он используется в качестве барьера синхронизации.
Я делаю что-то не так?
ДА. Не делай этого
while (!phaser.isTerminated()) {}
Напряженное вращение убьет вас. Вместо этого сделайте:
phaser.awaitAdvance();
Это заставило бы вас зарегистрироваться немного по-другому. Вам нужно будет зарегистрировать поток, прежде чем вы действительно начнете работать.
Кроме того, если вы продвигаете фазер, где у вас есть несколько фаз, вам придется пересмотреть использование фазера.
Я думал, что это было бы полезным способом отслеживать завершение дочерних потоков и ждать их завершения?
Если у вас действительно создается несколько неизвестных потоков, было бы полезно использовать фазер.
Комментарии:
1. Спасибо, я удалил phaser.register() в делегаторе и просто поставил phaser.arriveAndAwaitAdvance() после вызова AnotherClass.createThreadDoWork(phaser), и все в порядке. Но это нормально только для одного вызова. Как только поступит второй запрос, который создаст новый фазер и начнет обработку, если исходный поток делегатора продвинет фазер, второй запрос / поток завершится. Есть идеи?
2. Документы Java 7 также, похоже, считают, что phaser.register(); в то время как (!phaser.isTerminated()) phaser.arriveAndAwaitAdvance(); является приемлемым подходом к использованию?
3. Это было бы лучше, поскольку вы не заняты вращением. Вы все еще ожидаете завершения работы фазеров.
4. Я думаю, главный вопрос в том, могут ли 2 экземпляра Phaser действовать независимо? т. Е., Если прибывают все стороны одного фазера, приводит ли это к увеличению фазы на другом? Или фаза каждого фазера специфична только для экземпляра этого фазера?
5. Последнее. Единственный случай, когда это неверно, — это если один фазер является родителем дочернего элемента (т. Е. :
new Phaser(new Phaser())
)