В Data Geekery мы любим Java. И так как мы действительно входим в свободный API jOOQ и запросы DSL , мы абсолютно взволнованы тем, что Java 8 принесет в нашу экосистему. Мы пару раз писали о приятных вкусностях Java 8 , и теперь мы чувствуем, что пришло время начать новую серию блогов,…
Ява 8 Пятница
Каждую пятницу мы показываем вам пару замечательных новых функций Java 8 в виде учебника, в которых используются лямбда-выражения, методы расширения и другие замечательные вещи. Вы найдете исходный код на GitHub .
Java 8 Goodie: Lean Concurrency
Кто-то однажды сказал, что (к сожалению, у нас больше нет источника):
Младшие программисты считают параллелизм трудным.
Опытные программисты считают параллелизм легким.
Старшие программисты считают параллелизм трудным.
Это совершенно верно. Но с другой стороны, Java 8, по крайней мере, улучшит ситуацию, упростив написание параллельного кода с помощью лямбд и множества улучшенных API. Давайте ближе посмотрим:
Java 8 улучшается на JDK 1.0 API
java.lang.Thread
была с самого начала в JDK 1.0. То же java.lang.Runnable
имеет java.lang.Runnable
, который будет аннотирован с помощью FunctionalInterface
в Java 8.
Это почти не представляет сложности, как мы можем наконец представить Runnable
s в Runnable
с этого Runnable
. Давайте предположим, что у нас есть длительная операция:
1
2
3
4
5
6
7
|
public static int longOperation() { System.out.println( "Running on thread #" + Thread.currentThread().getId()); // [...] return 42 ; } |
Затем мы можем передать эту операцию Threads
различными способами, например,
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
Thread[] threads = { // Pass a lambda to a thread new Thread(() -> { longOperation(); }), // Pass a method reference to a thread new Thread(ThreadGoodies::longOperation) }; // Start all threads Arrays.stream(threads).forEach(Thread::start); // Join all threads Arrays.stream(threads).forEach(t -> { try { t.join(); } catch (InterruptedException ignore) {} }); |
Как мы упоминали в нашем предыдущем посте в блоге, обидно, что лямбда-выражения не нашли простой способ обойти проверенные исключения. Ни один из недавно добавленных функциональных интерфейсов в пакете java.util.function
позволяет генерировать проверенные исключения, оставляя работу до call-сайта.
Таким образом, в нашем последнем посте мы опубликовали jOOλ (также jOOL, jOO-Lambda) , который оборачивает каждый из функциональных интерфейсов JDK в эквивалентный функциональный интерфейс, который позволяет создавать проверенные исключения. Это особенно полезно со старыми API JDK, такими как JDBC, или вышеупомянутым API-интерфейсом Thread. С помощью jOOλ мы можем написать:
1
2
3
4
|
// Join all threads Arrays.stream(threads).forEach(Unchecked.consumer( t -> t.join() )); |
Java 8 улучшается на Java 5 API
Многопоточные API Java были довольно бездействующими вплоть до выпуска потрясающего ExecutorService
в Java 5. Управление потоками было обременительным, и людям требовались внешние библиотеки или J2EE / JEE-контейнер для управления пулами потоков. Это стало намного проще с Java 5. Теперь мы можем отправить Runnable
или Callable
в ExecutorService
, который управляет своим собственным пулом потоков.
Вот пример того, как мы можем использовать эти API параллелизма Java 5 в Java 8:
01
02
03
04
05
06
07
08
09
10
11
|
ExecutorService service = Executors .newFixedThreadPool( 5 ); Future[] answers = { service.submit(() -> longOperation()), service.submit(ThreadGoodies::longOperation) }; Arrays.stream(answers).forEach(Unchecked.consumer( f -> System.out.println(f.get()) )); |
Обратите внимание, как мы снова используем UncheckedConsumer из jOOλ, чтобы обернуть проверенное исключение, выброшенное из вызова get()
в RuntimeException
.
Параллелизм и ForkJoinPool в Java 8
Теперь API-интерфейс Java 8 Streams многое меняет с точки зрения параллелизма и параллелизма. Например, в Java 8 вы можете написать следующее:
1
2
3
4
|
Arrays.stream( new int []{ 1 , 2 , 3 , 4 , 5 , 6 }) .parallel() .max() .ifPresent(System.out::println); |
Хотя в данном конкретном случае это и не нужно, все же интересно видеть, что простой вызов функции parallel()
запустит операцию IntStream.max () на всех доступных потоках внутреннего ForkJoinPool вашего JDK, не беспокоясь о участвует ForkJoinTasks
. Это может быть действительно полезным, так как не все приветствовали API-интерфейс ForkJoin JDK 7 из-за его сложности .
Узнайте больше о параллельных потоках Java 8 в этой интересной статье InfoQ .
Подробнее о Java 8
Параллелизм был одной из главных движущих сил нового Streams API. Возможность установить флаг Stream parallel()
в Stream просто замечательна во многих ситуациях.
В последнем примере мы видели метод OptionalInt.ifPresent (), который принимает аргумент IntConsumer для выполнения в случае успешного выполнения предыдущей операции сокращения.
Другие языки, такие как Scala, знают тип «Option» для улучшения обработки NULL. Ранее мы писали о Optional и будем повторять тип Java 8 Optional
в контексте потоков Java 8, так что следите за обновлениями!
А пока взгляните на удивительную страницу ресурсов Java 8 от Eugen Paraschiv.
Ссылка: | Пятничные вкусности Java 8: Lean Concurrency от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ . |