Я обычный разработчик C #, но иногда я разрабатываю приложения на Java. Мне интересно, есть ли какой-нибудь Java-эквивалент C # async / await? Проще говоря, что такое Java-эквивалент:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
return urlContents.Length;
}
async
, но использованиеFuture
илиObservable
значений вместо этого.Ответы:
Нет, нет эквивалента async / await в Java - или даже в C # до v5.
Это довольно сложная языковая функция для создания конечного автомата за кулисами.
Существует относительно небольшая языковая поддержка асинхронности / параллелизма в Java, но
java.util.concurrent
пакет содержит много полезных классов вокруг этого. (Не совсем эквивалентный параллельной библиотеке задач, но наиболее близкий к ней.)источник
await
Использует продолжение , чтобы выполнить дополнительный код , когда асинхронная операция завершается (client.GetStringAsync(...)
).Таким образом, в качестве наиболее близкого приближения я бы использовал решение на основе
CompletableFuture<T>
(эквивалент Java. 8Task<TResult>
) для асинхронной обработки запроса Http.ОБНОВЛЕНО 25-05-2016 до версии AsyncHttpClient v.2, выпущенной 13 апреля 2016 года:
Таким образом, Java 8, эквивалентный примеру OP,
AccessTheWebAsync()
выглядит следующим образом:Это использование было взято из ответа на Как получить CompletableFuture из запроса Async Http Client? и который соответствует новому API, предоставленному во второй версии AsyncHttpClient, выпущенной 13 апреля 2016 года, которая уже имеет встроенную поддержку
CompletableFuture<T>
.Исходный ответ с использованием версии 1 AsyncHttpClient:
Для этого у нас есть два возможных подхода:
первый использует неблокирующий ввод-вывод, и я это называю
AccessTheWebAsyncNio
. Тем не менее, посколькуAsyncCompletionHandler
это абстрактный класс (а не функциональный интерфейс), мы не можем передать лямбду в качестве аргумента. Таким образом, это неизбежно связано с синтаксисом анонимных классов. Однако это решение наиболее близко к потоку выполнения данного примера C # .второй вариант немного менее многословен, однако он отправит новую задачу, которая в конечном итоге заблокирует поток
f.get()
до тех пор, пока ответ не будет завершен.Первый подход , более многословный, но не блокирующий:
Второй подход менее многословен, но блокирует поток:
источник
Проверьте ea-async, который выполняет переписывание байт-кода Java для имитации async / await довольно красиво. Согласно их readme: «Это вдохновлено Async-Await в .NET CLR»
источник
async и await являются синтаксическими сахарами. Суть асинхронности и ожидания - конечный автомат. Компилятор преобразует ваш асинхронный / ожидающий код в конечный автомат.
В то же время, для того, чтобы async / await реально применялся в реальных проектах, нам необходимо иметь множество функций библиотеки ввода-вывода Async . Для C # большинство оригинальных синхронизированных функций ввода / вывода имеет альтернативную асинхронную версию. Причина, по которой нам нужны эти асинхронные функции, заключается в том, что в большинстве случаев ваш собственный асинхронный / ожидающий код сводится к некоторому библиотечному асинхронному методу.
Функции библиотеки версий Async в C # подобны концепции AsynchronousChannel в Java. Например, у нас есть AsynchronousFileChannel.read, который может либо вернуть Future, либо выполнить обратный вызов после завершения операции чтения. Но это не совсем то же самое. Все функции C # Async возвращают Задачи (аналогично Future, но более мощные, чем Future).
Допустим, Java поддерживает async / await, и мы напишем некоторый код, подобный следующему:
Тогда я бы предположил, что компилятор преобразует исходный код async / await во что-то вроде этого:
А вот реализация для AsyncHandler:
источник
На уровне языка нет эквивалента C # async / await в Java. Концепция, известная как Fibers или кооперативные нити, или легкие нити, может быть интересной альтернативой. Вы можете найти библиотеки Java, обеспечивающие поддержку волокон.
Библиотеки Java, реализующие Fibers
Вы можете прочитать эту статью (от Quasar) для хорошего знакомства с волокнами. Он описывает, что такое потоки, как волокна могут быть реализованы в JVM, и содержит некоторый специфичный для Quasar код.
источник
Task
классе) путем регистрации обратного вызова.Как было упомянуто, прямого эквивалента нет, но очень близкое приближение можно было бы создать с помощью модификаций байт-кода Java (как для асинхронных / await-подобных инструкций, так и для реализации базовых продолжений).
Сейчас я работаю над проектом, который реализует async / await поверх библиотеки продолжения JavaFlow , пожалуйста, проверьте https://github.com/vsilaev/java-async-await
Maven mojo еще не создан, но вы можете запускать примеры с помощью поставляемого Java-агента. Вот как выглядит асинхронный / ожидающий код:
@async - это аннотация, помечающая метод как асинхронно исполняемый, await () - это функция, которая ожидает CompletableFuture с использованием продолжений, а вызов «return asyncResult (someValue)» - это то, что завершает связанный CompletableFuture / Continuation
Как и в C #, поток управления сохраняется, и обработка исключений может выполняться обычным образом (try / catch, как в последовательно выполняемом коде)
источник
Сама Java не имеет эквивалентных функций, но существуют сторонние библиотеки, которые предлагают аналогичные функции, например, Kilim .
источник
Во-первых, понять, что такое async / await. Это позволяет однопоточному приложению с графическим интерфейсом или эффективному серверу запускать несколько «волокон», «подпрограмм» или «облегченных потоков» в одном потоке.
Если вы согласны с использованием обычных потоков, то эквивалент Java есть
ExecutorService.submit
иFuture.get
. Это заблокирует, пока задача не завершится, и вернет результат. Между тем, другие темы могут делать работу.Если вы хотите использовать преимущества чего-то вроде волокон, вам нужна поддержка в контейнере (я имею в виду в цикле событий GUI или в обработчике HTTP-запросов сервера) или при написании собственного.
Например, Servlet 3.0 предлагает асинхронную обработку. JavaFX предлагает
javafx.concurrent.Task
. Они не имеют элегантности языковых особенностей, хотя. Они работают через обычные обратные вызовы.источник
В Java нет ничего такого, что позволяло бы вам делать это, например, ключевые слова async / await, но что вы можете сделать, если действительно хотите, это использовать CountDownLatch . Затем вы можете имитировать async / await, передавая это (по крайней мере, в Java7). Это обычная практика в модульном тестировании Android, когда мы должны сделать асинхронный вызов (обычно это исполняемый файл, отправленный обработчиком), а затем дождаться результата (обратный отсчет).
Однако использование этого в вашем приложении в отличие от вашего теста НЕ является тем, что я рекомендую. Это было бы крайне некачественно, поскольку CountDownLatch зависит от того, насколько эффективно вы отсчитываете нужное количество раз и в нужных местах.
источник
Я делаю и выпускаю библиотеку Java async / await. https://github.com/stofu1234/kamaitachi
Эта библиотека не нуждается в расширении компилятора и реализует обработку ввода-вывода без стеков в Java.
↓
источник
К сожалению, Java не имеет эквивалента async / await. Самое близкое, что вы можете получить, это, вероятно, с ListenableFuture из Guava и цепочкой слушателей, но было бы все еще очень громоздко писать для случаев, связанных с несколькими асинхронными вызовами, так как уровень вложенности очень быстро рос.
Если вы согласны с использованием другого языка поверх JVM, к счастью, в Scala есть async / await, который является прямым C # async / await эквивалентом с почти идентичным синтаксисом и семантикой: https://github.com/scala/ асинхронный /
Обратите внимание, что хотя для этой функциональности требовалась довольно продвинутая поддержка компилятора в C #, в Scala ее можно было добавить в виде библиотеки благодаря очень мощной макросистеме в Scala и, следовательно, ее можно добавить даже в более старые версии Scala, такие как 2.10. Кроме того, Scala совместима с классами с Java, поэтому вы можете написать асинхронный код в Scala и затем вызывать его из Java.
Существует также другой аналогичный проект под названием Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html, который использует другую формулировку, но концептуально очень похож, однако реализован с использованием продолжения с разделителями, а не макросов. (поэтому он работает даже с более старыми версиями Scala, такими как 2.9).
источник
Java не имеет прямого эквивалента возможности языка C # под названием async / await, однако существует другой подход к проблеме, которую пытается решить async / await. Он называется проектом Loom , который будет предоставлять виртуальные потоки для высокопроизводительного параллелизма. Он будет доступен в некоторых будущих версиях OpenJDK.
Этот подход также решает " проблему цветных функций ", которая есть у async / await.
Подобная особенность также может быть найдена в Golang ( goroutines ).
источник
Если вам нужен только чистый код, который имитирует тот же эффект, что и async / await в java, и не возражаете против блокировки потока, к которому он вызывается, до его завершения, например, в тесте, вы можете использовать что-то вроде этого кода:
источник
Библиотека Java AsynHelper включает в себя набор служебных классов / методов для таких асинхронных вызовов (и ожидания).
Если необходимо выполнить набор вызовов методов или блоков кода асинхронно, он включает полезный вспомогательный метод AsyncTask .submitTasks, как показано ниже.
Если необходимо дождаться завершения выполнения всех асинхронных кодов, можно использовать переменную AsyncTask.submitTasksAndWait .
Кроме того, если необходимо получить возвращаемое значение из каждого асинхронного вызова метода или блока кода, можно использовать AsyncSupplier .submitSuppliers , чтобы затем можно было получить результат из массива поставщиков результатов, возвращенного методом. Ниже приведен образец фрагмента:
Если тип возвращаемого значения каждого метода отличается, используйте приведенный ниже фрагмент кода.
Результат асинхронных вызовов методов / блоков кода также может быть получен в другой точке кода в том же потоке или в другом потоке, как в приведенном ниже фрагменте кода.
источник