Есть довольно много мест, где вы можете воспользоваться @Asynchronous.С помощью этой аннотации вы можете написать свое приложение в соответствии со спецификацией Java EE;не используйте явное многопоточность, но позвольте работе, выполняемой управляемыми пулами потоков.
Во-первых, вы можете использовать это для действий "запусти и забудь".Например, отправка электронного письма пользователю может быть выполнена аннотированным методом @Asynchronous.Пользователю не нужно ждать, пока ваш код свяжется с почтовым сервером, договориться о протоколе и т. Д. Это пустая трата времени, чтобы позволить основному потоку обработки запросов ждать этого.
Аналогично, возможно, вывыполните некоторые контрольные записи, когда пользователь входит в ваше приложение и снова выходит из системы.Оба эти постоянных действия являются идеальными кандидатами для использования в асинхронных методах.Бессмысленно позволять пользователю ждать такого внутреннего администрирования.
Тогда есть класс ситуаций, когда вам нужно выбрать несколько элементов данных, которые нельзя (легко) извлечь с помощью одного запроса.Например, я часто вижу приложения, которые выполняют:
User user = userDAO.getByID(userID);
Invoice invoice = invoiceDAO.getByUserID(userID);
PaymentHistory paymentHistory = paymentDAO.getHistoryByuserID(userID);
List<Order> orders = orderDAO.getOpenOrdersByUserID(userID);
Если вы выполните это как есть, ваш код сначала пойдет в БД и будет ждать выборки пользователя.Он сидит без дела между ними.Затем он отправится за счетом и снова ждет.И т. Д.
Это можно ускорить, выполнив эти отдельные вызовы асинхронно:
Future<User> futureUser = userDAO.getByID(userID);
Future<Invoice> futureInvoice = invoiceDAO.getByUserID(userID);
Future<PaymentHistory> futurePaymentHistory = paymentDAO.getHistoryByuserID(userID);
Future<List<Order>> futureOrders = orderDAO.getOpenOrdersByUserID(userID);
Как только вам действительно понадобится один из этих объектов, код автоматически заблокируется, если результат нееще нет.Это позволяет перекрывать выборку отдельных элементов и даже перекрывать другую обработку при выборке.Например, ваш жизненный цикл JSF уже может пройти несколько этапов, пока вам действительно не понадобится какой-либо из этих объектов.
Обычный совет, что многопоточное программирование трудно отлаживать, здесь не применим.Вы не осуществляете какой-либо явной связи между потоками, и вы даже сами не создаете никаких потоков (это две основные проблемы, на которых основан этот исторический совет).
В следующем случае использование асинхронного выполнения было бы бесполезным:
Future<user> futureUser = userDAO.getUserById(userId);
User user = futureUser.get(); // block happens here
user.setCount(user.getCount() + 1);
Если вы делаете что-то асинхронно и сразу после этого ожидаете результат, чистый эффект - это последовательный вызов.
вернет ли пользователь строку;блок для ожидания асинхронного userDAO.merge (user)
Боюсь, вы еще не до конца его поняли.Оператор return не знает, какая операция выполняется для экземпляра, обрабатываемого в другом контексте.Это не то, как работает Java.
В моем предыдущем примере метод getUserByID
вернул Future .Код автоматически блокируется при операции get()
.
Так что если у вас есть что-то вроде:
public class SomeBean {
Future<User> futureUser;
public String doStuff() {
futureUser = dao.getByID(someID);
return "";
}
public getUser() {
return futureUser.get(); // blocks in case result is not there
}
}
Затем в случае нажатия кнопки AJAX-запроса и вывода outputText с помощьюпривязка к someBean.user
, тогда нет условий гонки.Если дао уже сделал свое дело, futureUser немедленно вернет экземпляр типа User.В противном случае он будет автоматически блокироваться до тех пор, пока экземпляр User не станет доступен.
Относительно выполнения асинхронной операции merge()
в вашем примере;это может столкнуться с условиями гонки.Если ваш компонент находится в области видимости, и пользователь быстро нажимает кнопку еще раз (например, возможно, дважды щелкнув первый раз), прежде чем будет выполнено первоначальное слияние, приращение может произойти в том же экземпляре, в котором первый вызов слияния все еще сохраняется.
В этом случае вам необходимо сначала клонировать объект User перед отправкой его в асинхронную операцию слияния.
Простые примеры, с которых я начал этот ответ, довольно безопасны, поскольку они предназначены для выполнения изолированногодействие или выполнение чтения с неизменным типом (userID, предположим, что это int или String) в качестве входных данных.
Как только вы начнете передавать изменяемые данные в асинхронные методы, вы должны быть абсолютно уверены, что впоследствии эти данные не будут изменены, иначе придерживайтесь простого правила, чтобы передавать только неизменяемые данные.