Ф'ючерси
Ф'ючерси були представлені на Java 5 (2004). Вони в основному є заповнювачами в результаті операції, яка ще не закінчилася. Як тільки операція закінчиться, заголовок Future
буде містити цей результат. Наприклад, операція може бути екземпляром Runnable або Callable, який передається в ExecutorService . Подаючий операції може використовувати Future
об’єкт, щоб перевірити, чи є операціяDone () , або чекати, коли вона закінчиться, використовуючи метод блокування get () .
Приклад:
/**
* A task that sleeps for a second, then returns 1
**/
public static class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
return 1;
}
}
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<Integer> f = exec.submit(new MyCallable());
System.out.println(f.isDone()); //False
System.out.println(f.get()); //Waits until the task is done, then prints 1
}
Комплектація
CompletableFutures були представлені в Java 8 (2014). Насправді вони є еволюцією регулярних ф'ючерсів, натхнених послугами Google « Listenable Futures» , що є частиною бібліотеки Guava . Вони є майбутніми, які також дозволяють складати завдання ланцюжка разом. Ви можете використовувати їх, щоб сказати робочій нитці "перейти виконувати якусь задачу X, і коли ви закінчите, виконайте цю іншу справу, використовуючи результат X". Використовуючи CompletableFutures, ви можете зробити щось з результатом операції, фактично не блокуючи нитку, щоб чекати результату. Ось простий приклад:
/**
* A supplier that sleeps for a second, and then returns one
**/
public static class MySupplier implements Supplier<Integer> {
@Override
public Integer get() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//Do nothing
}
return 1;
}
}
/**
* A (pure) function that adds one to a given Integer
**/
public static class PlusOne implements Function<Integer, Integer> {
@Override
public Integer apply(Integer x) {
return x + 1;
}
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newSingleThreadExecutor();
CompletableFuture<Integer> f = CompletableFuture.supplyAsync(new MySupplier(), exec);
System.out.println(f.isDone()); // False
CompletableFuture<Integer> f2 = f.thenApply(new PlusOne());
System.out.println(f2.get()); // Waits until the "calculation" is done, then prints 2
}
RxJava
RxJava - ціла бібліотека для реактивного програмування, створена в Netflix. З першого погляду це буде схоже на потоки Java 8 . Воно, хіба що набагато потужніше.
Аналогічно до Futures, RxJava може використовуватися для з'єднання купу синхронних або асинхронних дій для створення конвеєра для обробки. На відміну від Futures, які одноразові, RxJava працює на потоках нульових або більше предметів. Включаючи нескінченні потоки з нескінченною кількістю елементів. Це також набагато гнучкіше і потужніше завдяки неймовірно багатому набору операторів .
На відміну від потоків Java 8, RxJava також має механізм зворотного тиску , що дозволяє йому обробляти випадки, коли різні частини обробного трубопроводу працюють в різних потоках , з різною швидкістю .
Мінусом RxJava є те, що, незважаючи на обґрунтовану документацію, бібліотеці є складною мірою вчитися завдяки зміні парадигми. Код Rx також може бути кошмаром для налагодження, особливо якщо задіяно декілька потоків, а ще гірше - якщо потрібен зворотний тиск.
Якщо ви хочете ввійти в нього, на офіційному веб-сайті є ціла сторінка різних навчальних посібників, а також офіційна документація та Javadoc . Ви також можете подивитися деякі відео, наприклад, це, яке дає короткий вступ у Rx, а також розповідає про відмінності між Rx та Futures.
Бонус: реактивні потоки Java 9
Реактивні Потоки Java 9 в аке Flow API є набором інтерфейсів реалізовані з допомогою різних реактивних потоків бібліотек , таких як RxJava 2 , Akka Streams і VertX . Вони дозволяють цим реактивним бібліотекам взаємозв'язуватися, зберігаючи всі важливі тиску.