- Java async await
- How does the async-await function work in Java?
- Examples of Java async await
- Example #1
- Example #2
- Example #3
- Example #4 – Time seconds
- Conclusion
- Recommended Articles
- Running a Task Asynchronously in Java With CompletableFuture
- Асинхронность в Java
- Синхронность vs асинхронность
- Синхронность:
- Асинхронность:
- Асинхронность с потоками
- Асинхронность с Future
- Асинхронность с CompletableFuture
- Асинхронность с @Async
- События Spring
- Микросервисы
- Плюсы и минусы асинхронности
- И последнее
Java async await
Java Asynchronous await is defined as performing I/O bound operations and doesn’t need any application responsiveness. These functions are normally used in file and network operations as they require callbacks executed on operation completion; also that this function always returns a value. With the help of the awake keyword, asynchronous calls are used inside regular control flow statements, and it is a non-blocking code. In this topic, we are going to learn about Java async await.
Web development, programming languages, Software testing & others
The general signature of async / await is given as
The await goes on like
How does the async-await function work in Java?
Async awaits function helps write synchronous code while performing async tasks behind the code. And we need to have the async keyword. And next is the awaited part that says to run the asynchronous code normally and proceed to the next line of code. The new operator “Await” automatically waits for a promise to resolve the running process when used inside an async function. However, it causes syntax errors when used in any other case.
If the function throws an error in error handling, the async function’s promise will reject. If the respective function happens to return a value, the promise will be solved. This non-blocking code runs on a separate thread and notifies the main thread about its completion or failure of a task. Try-catch is used in a function to handle the errors synchronously. Let’s take a sample beginning like
async function hello() < //process waiting await new Promise(res =>setTimeout(res, 2000)); // Rejection with 20 % if (Math.random() > 0.2) < throw new Error('Check the number.') >return 'number'; >
The above code says that the function hello() is async, resolves it by returning a number, and throws an error by checking the number.
Next, using await and return together to suspend a process
async function miss() < try < return await hello(); >catch (e) < return 'error caught'; >>
Better promising chaining with this function is given as
async function promise1( req,res) < try < let a=await a.get(req,uid); let b=await cart.get (yser,uid); Res.send(await dosome(a,cart)); >catch (err) < res.send(err); >>
So here await keyword instructs the function get () to complete before catching an error.
With this Completable future, it returns a future object. This Completable future is a reference to asynchronous computation and implements the future.
private static CompletableFuture hello < try < String intermediate = await(doA()); String res = await(doB(intermediate)); reportSuccess(res); >catch (Throwable th) < reportFailure(th); >return completedFuture(null); >
Examples of Java async await
So in this section, we will see how the finer points of async and await work here.
Example #1
import 'dart:async'; void main() async < var a = await ten(); print(a); >Future ten() async
Explanation
The above code uses the future, the Java 7 version API, and waits ten seconds to display 10.
Example #2
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; class Comput1 implements Runnable < public static int item = 0; public void run() < item = 3 * 3; try < CyclicBarrierAwaitExample2.newBarrier.await(); >catch (InterruptedException | BrokenBarrierException e) < e.printStackTrace(); >> > class Comput2 implements Runnable < public static int total = 0; public void run() < // check if newBarrier is broken or not System.out.println("Is it broken? - " + CyclicBarrierAwaitExample2.newBarrier.isBroken()); total = 20 + 20; try < CyclicBarrierAwaitExample2.newBarrier.await(2000, TimeUnit.MILLISECONDS); System.out.println("Number of rooms waiting at the barrier "+ "here = " + CyclicBarrierAwaitExample2.newBarrier.getNumberWaiting()); >catch (InterruptedException | BrokenBarrierException e) < e.printStackTrace(); >catch (TimeoutException e) < e.printStackTrace(); >> > public class CyclicBarrierAwaitExample2 implements Runnable < public static CyclicBarrier newBarrier = new CyclicBarrier(3); public static void main(String[] args) < CyclicBarrierAwaitExample2 test = new CyclicBarrierAwaitExample2(); Thread t = new Thread(test); t.start(); >@Override public void run() < System.out.println("Number of parties required to trip the barrier = "+ newBarrier.getParties()); System.out.println("Sum of product and sum = " + (Comput1.item + Comput2.total)); Comput1 comp1 = new Comput1(); Comput2 comp2 = new Comput2(); Thread t = new Thread(comp1); Thread t2 = new Thread(comp2); t.start(); t2.start(); TimeUnit unit = TimeUnit.SECONDS; try < CyclicBarrierAwaitExample2.newBarrier.await(1,unit); >catch (InterruptedException | BrokenBarrierException | TimeoutException e) < e.printStackTrace(); >System.out.println("Sum of item and total = " + (Comput1.item + Comput2.total)); newBarrier.reset(); System.out.println(" reset successful"); > >
Explanation
While the other thread is processing a task, the value is summed up.
Example #3
import java.util.*; import java.util.concurrent.*; public class Async < static Listtasks = new ArrayList<>(); static ExecutorService executor = Executors.newScheduledThreadPool(3); public static void main(String[] args) < createTasks(); executeTasks(); >private static void createTasks() < for (int k= 0; k < 10; k++) < tasks.add(new Task(k)); >> private static void executeTasks() < for (Task task : tasks) < executor.submit(task); >> static class Task extends Thread < int n; public void run() < try < Thread.sleep(new Random (). nextInt (1000)); >catch (InterruptedException e) < e.printStackTrace(); >printNum(); > private void printNum() < System.out.print(n + " "); >public Task(int n) < this.n = n; >> >
Explanation
The above code initiates a task by assigning a thread value, i.e., a worker thread. Here we stop the synchronous task in the print numb() function. Therefore, the output looks like this:
Example #4 – Time seconds
Understanding JavaScript Program Execution
Explanation
The above code executes its promises and shows their wait time interval with the help of async-await. For example, the script above waits for 20 sec to complete the task.
Conclusion
Coming to an end, writing asynchronous code is a little harder, and most- importantly, promises are the general way to define the flow of delayed execution. In this article, we learned how to write asynchronous code that looks like synchronous. Using async has been more important in complex code. The JavaScript developer must understand much about this concept.
Recommended Articles
We hope this EDUCBA information on “Java async await” was beneficial to you. You can view EDUCBA’s recommended articles for more information.
89+ Hours of HD Videos
13 Courses
3 Mock Tests & Quizzes
Verifiable Certificate of Completion
Lifetime Access
4.5
97+ Hours of HD Videos
15 Courses
12 Mock Tests & Quizzes
Verifiable Certificate of Completion
Lifetime Access
4.5
JAVA Course Bundle — 78 Courses in 1 | 15 Mock Tests
416+ Hours of HD Videos
78 Courses
15 Mock Tests & Quizzes
Verifiable Certificate of Completion
Lifetime Access
4.8
Running a Task Asynchronously in Java With CompletableFuture
Here’s how to use CompletableFuture to run a task asynchronously in Java.
import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.logging.Level; import java.util.logging.Logger; import static java.util.concurrent.TimeUnit.SECONDS; public class AsyncTask < private static final Logger LOGGER = Logger.getLogger(AsyncTask.class.getName()); public static void main(String[] args) < CompletableFuture.runAsync(AsyncTask::task); LOGGER.info("Message from the main thread. Note that this message is logged before the async task ends."); LOGGER.info("Waiting for the async task to end."); boolean isQuiecent = ForkJoinPool.commonPool().awaitQuiescence(5, SECONDS); if (isQuiecent) < LOGGER.info("Async task ended."); >else < LOGGER.log(Level.SEVERE, "The async task is taking too long to finish. This program will end anyway."); >> private static void task() < LOGGER.info("Async task starting. This message is logged by the async task thread"); try < Thread.sleep(1000); LOGGER.info("Async task is ending. This message is logged by the async task thread"); >catch (InterruptedException e) < Thread.currentThread().interrupt(); LOGGER.log(Level.SEVERE, "The async task thread was interrupted.", e); >> >
If you have any questions, leave a comment or ask me on my social media.
Асинхронность в Java
Асинхронное программирование — обширная и получившая широкое обсуждение тема, но инженеры-программисты все еще ищут, как лучше реализовать эту идею и интегрировать в приложения.
Мне — старшему инженеру-программисту — стало любопытно, как возможно делать несколько вещей одновременно, и задаюсь этим вопросом наверняка не только я. Каждый стремится быть более продуктивным и хочет того же от своих приложений.
Переключив внимание на асинхронность в Java, мы откроем для себя множество способов ее реализации и различные варианты использования.
Синхронность vs асинхронность
Синхронное (Sync) и асинхронное (Async) программирование может выполняться как в одном, так и в нескольких потоках. Основное различие между в том, что при синхронном программирования мы выполняем одну задачу за раз, а при асинхронном программировании — несколько задач выполняются одновременно. Например:
Синхронность:
- Однопоточность: я начинаю варить яйцо. После того как оно сварится, я могу начать поджаривать хлеб. Мне приходится ждать завершения одной задачи, чтобы начать другую.
- Многопоточность: я начинаю варить яйцо, а после того как оно сварится, моя мама поджарит хлеб. Задачи выполняются одна за другой и разными лицами (потоками).
Асинхронность:
- Однопоточность: я ставлю яйцо вариться и устанавливаю таймер, кладу хлеб в тостер и запускаю другой таймер, а когда время выйдет — я буду есть. В асинхронном режиме мне не нужно ждать завершения задачи, чтобы начать еще одну.
- Многопоточность: я нанимаю двух поваров, чтобы они сварили для меня яйцо и поджарили хлеб. Они могут делать это одновременно, и один не должен ждать другого, чтобы начать.
Асинхронность с потоками
Первый способ реализовать асинхронность в Java — воспользоваться интерфейсом Runnable и классом потока Thread , который доступен начиная с JDK 1.0. Любой класс может реализовать Runnable и переопределить метод run() либо расширить класс Thread и сделать то же самое.
Разница в том, что когда метод run вызывается непосредственно из Runnable , не создается новый поток, а метод выполняется в потоке, откуда вызван. Однако, если мы воспользуемся thread.start() , будет создан новый поток.
Для лучшего управления потоками в JDK 1.5 можно задействовать исполнителей ( Executor ). Они используют разные пулы потоков и помогают избежать необходимости вручную создавать поток. Вместо этого можно указать, сколько потоков нам нужно, и исполнитель будет переиспользовать эти потоки в течение всего времени запуска приложения.
Асинхронность с Future
run() — это void-метод, и он не может ничего возвращать из потока, но если нам нужен результат вычисления, выполняемого в другом потоке, чем main , то нужно будет воспользоваться интерфейсом Callable . Ответ от задачи недоступен немедленно, и в качестве альтернативы Callable вернет будущий объект Future , когда он будет отправлен в службу выполнения. Этот объект обещает, что, когда вычисления завершатся, мы получим их результат — достаточно только вызвать get() . Это не очень хорошее применение асинхронности, так как get() блокирует текущий поток до тех пор, пока не получит ответ. Однако существует обходной путь через метод future.isDone() — он постоянно проверяет, завершено ли вычисление, и только когда этот метод вернет значение true , get() возвратит результат.
Асинхронность с CompletableFuture
В JDK 1.8 объект Future получил обновление и стал объектом CompletableFuture , который, помимо будущего объекта, также реализует этап завершения ( CompletionStage ). CompletionStage предлагает множество методов для упрощения работы с ответами, вычисленными в разных потоках и этапах. Некоторые из наиболее распространенных — это thenApply() , аналогичная функции map() из потоков, а также thenAccept() , аналогичная функции foreach . Существует несколько способов получить ответ CompletableFuture . Одни выполняют задачу в другом потоке, другие нет, но их объединяет одно — если во время вычисления возникнут исключения, пользователи могут обрабатывать их.
Асинхронность с @Async
Другой способ реализации асинхронности — аннотация @Async из Spring Framework. Ее можно задействовать только в публичных методах, и в этом случае вызов методов из того же класса, в котором они определены, будет недоступен. Любой код, находящийся внутри метода с аннотацией @Async , будет выполняться в другом потоке и может быть недействительным или возвращать CompletableFuture . Таким образом, это альтернатива созданию CompletableFuture и предоставлению ему метода для запуска, но чтобы иметь возможность использовать эту аннотацию, необходимо другое: @EnableAsync в классе конфигурации.
События Spring
События Spring для реализации асинхронности — это шаг вперед, который также предлагает способ снижения связности и простоту добавления новых функций без изменения существующих.
- Событие ( Event ) — может быть любым объектом, расширяющим ApplicationEvent .
- Издатель ( Publisher ) — компонент, который опубликует событие с помощью компонента ApplicationEventPublisher .
- Прослушиватель ( Listener ) — компонент, который содержит метод с аннотацией @EventListener , и помогает определить задачу, которая выполнится при возникновении определенного события.
По умолчанию метод прослушивателя выполняется синхронно, но это легко изменить, применив аннотацию @Async .
Другой способ сделать прослушиватель асинхронным — добавить в конфигурацию компонент с SimpleApplicationEventMulticaster и назначить ему TaskExecutor . Когда этот компонент на месте, не нужно аннотировать каждый список событий с помощью @Async , и все события будут сами обрабатываться в другом потоке. Если не хочется пропустить аннотацию @Async для какого-то метода, будет полезно воспользоваться этим способом, но имейте в виду: такой подход сделает асинхронной обработку всех событий, даже событий фреймворка. Использование аннотации позволит нам выбрать, какие события будут обрабатываться синхронно, а какие асинхронно.
Микросервисы
На уровне микросервисов также есть возможность выбирать между синхронностью и асинхронностью. Разница между ними в том, что, как и сказано в определении, асинхронность означает, что мы не ждем немедленного ответа от вызываемой службы, в то время как синхронность означает, что ждем.
Одна из самых популярных синхронных коммуникаций между микросервисами — через вызовы REST. Для асинхронной связи можно воспользоваться очередями или темами. И те, и другие содержат сообщения, но отличие в том, что сообщение из очереди может быть обработано только одним подписчиком, а сообщение из темы может быть прочитано несколькими подписчиками.
Плюсы и минусы асинхронности
Об асинхронном программировании стоит задуматься, когда вы хотите делегировать задачу другому потоку, поскольку она отнимает много времени, или не хотите, чтобы результат задачи влиял на текущий поток приложения. Так получится выполнять несколько операций одновременно. Используя асинхронность, вы можете разделять задачи и компоненты, что приводит к повышению общей производительности приложения.
В качестве альтернативы необходимо знать, что в коде с асинхронными методами усложняются отладка и написание тестов, но это не должно становиться препятствием при выборе решения.
И последнее
Потоки — это о работниках (воркерах), а асинхронность — это о задачах!