diff --git a/README.md b/README.md index 9dda8e6..7b5ea89 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Java8 改变了我们思考和编码的方式,在这里你可以学习到 Java8 中的核心特性以及使用场景,跟我学习 Java8,让你的编程更轻松! [![Travis Build](https://travis-ci.org/biezhi/learn-java8.svg?branch=master)](https://travis-ci.org/biezhi/learn-java8) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![License](https://img.shields.io/badge/license-BSD--3-blue.svg)](https://github.com/biezhi/learn-java8/blob/master/LICENSE) [![@biezhi on zhihu](https://img.shields.io/badge/zhihu-%40biezhi-red.svg)](https://www.zhihu.com/people/biezhi) [![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/biezhii.svg?style=social&label=Follow%20Twitter)](https://twitter.com/biezhii) @@ -31,8 +30,8 @@ Java8 改变了我们思考和编码的方式,在这里你可以学习到 Java |第 9 课 | [Stream API(上)](https://github.com/biezhi/learn-java8/blob/master/java8-stream/README.md#%E4%BD%BF%E7%94%A8%E6%B5%81) | [网易云课堂](http://study.163.com/course/courseLearn.htm?courseId=1005047049&utm_campaign=commission&utm_source=cp-400000000397038&utm_medium=share#/learn/video?lessonId=1051566020&courseId=1005047049) ¦ [哔哩哔哩](https://www.bilibili.com/video/av19287893/index_9.html#page=9) ¦ [Youtube](https://youtu.be/mGwFJERNzmY) | [stream](https://github.com/biezhi/learn-java8/blob/master/java8-stream/src/main/java/io/github/biezhi/java8/stream/lesson2) | |第 10 课 | [Stream API(下)](https://github.com/biezhi/learn-java8/blob/master/java8-stream/README.md#collector-%E6%94%B6%E9%9B%86) | [网易云课堂](http://study.163.com/course/courseLearn.htm?courseId=1005047049&utm_campaign=commission&utm_source=cp-400000000397038&utm_medium=share#/learn/video?lessonId=1051571684&courseId=1005047049) ¦ [哔哩哔哩](https://www.bilibili.com/video/av19287893/index_10.html#page=10) ¦ [Youtube](https://youtu.be/iubE0ezu-xI) | [stream](https://github.com/biezhi/learn-java8/tree/master/java8-stream/src/main/java/io/github/biezhi/java8/stream/lesson3) | |第 11 课 | [新的日期时间 API](https://github.com/biezhi/learn-java8/blob/master/java8-datetime-api/README.md) | [网易云课堂](http://study.163.com/course/courseLearn.htm?courseId=1005047049&utm_campaign=commission&utm_source=cp-400000000397038&utm_medium=share#/learn/video?lessonId=1051571688&courseId=1005047049) ¦ [哔哩哔哩](https://www.bilibili.com/video/av19287893/index_11.html#page=11) ¦ [Youtube](https://youtu.be/hKXJvh-id1E) | [datetime](https://github.com/biezhi/learn-java8/tree/master/java8-datetime-api/src/main/java/io/github/biezhi/datetime) | -|第 12 课 | 并发增强 | 网易云课堂 ¦ 哔哩哔哩 ¦ Youtube | | -|第 13 课 | CompletableFuture | 网易云课堂 ¦ 哔哩哔哩 ¦ Youtube | | +|第 12 课 | [并发增强](https://github.com/biezhi/learn-java8/blob/master/java8-concurrent/README.md) | [网易云课堂](http://study.163.com/course/courseLearn.htm?courseId=1005047049&utm_campaign=commission&utm_source=cp-400000000397038&utm_medium=share#/learn/video?lessonId=1051682806&courseId=1005047049) ¦ [哔哩哔哩](https://www.bilibili.com/video/av19287893/index_12.html#page=12) ¦ [Youtube](https://youtu.be/OYkToWIDEEI) | [concurrent](https://github.com/biezhi/learn-java8/tree/master/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent) | +|第 13 课 | [CompletableFuture](https://github.com/biezhi/learn-java8/blob/master/java8-completablefuture/README.md) | [网易云课堂](http://study.163.com/course/courseLearn.htm?courseId=1005047049&utm_campaign=commission&utm_source=cp-400000000397038&utm_medium=share#/learn/video?lessonId=1051908792&courseId=1005047049) ¦ [哔哩哔哩](https://www.bilibili.com/video/av19287893/index_13.html#page=13) ¦ [Youtube](https://youtu.be/4reRygD1dGo) | [completablefuture](https://github.com/biezhi/learn-java8/tree/master/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture) | |第 14 课 | Nashorn 引擎 | 网易云课堂 ¦ 哔哩哔哩 ¦ Youtube | | |第 15 课| Java 8 最佳实践 | 网易云课堂 ¦ 哔哩哔哩 ¦ Youtube | | |第 16 课| 函数式编程的正确姿势 | 网易云课堂 ¦ 哔哩哔哩 ¦ Youtube | | diff --git a/java8-completablefuture/README.md b/java8-completablefuture/README.md new file mode 100644 index 0000000..720b159 --- /dev/null +++ b/java8-completablefuture/README.md @@ -0,0 +1,114 @@ +# CompletableFuture + +## 为什么要引入 CompletableFuture + +- Future.get() 方法会阻塞线程,一直阻塞,直到其所对应的任务完成或因为异常退出。在不恰当的地方调用此方法会因为线程阻塞而降低系统响应度。就像文中提到的。 +- Future.get(long, TimeUnit) 可以一定的时间内超时退出,而不会像前一个方法那样一直阻塞线程。但是这对系统响应性的改进是治标不治本。 +- Java 8 引入了 CompletableFuture,可用通过 CompletableFuture thenAccept(Consumer action) 方法异步触发 send(Response) 方法。这时 serve() 方法会很快结束。而当 responseFuture 所对应的任务完成时,send(Response) 方法便会被调用,其执行线程同 responseFuture 所对应的任务的执行线程相同。 +- 对于上一点,有人会问,何必这么麻烦?直接在 responseFuture 所对应任务 (Runnable or Callable) 里面调用 send(Response) 方法。各种在实际工作中可能会遇到的问题暂且不说。只说两点: + 1. responseFuture 所对应任务是不可修改的,比如调用自第三方模块 + 2. 即便代码可修改,但在 responseFuture 所对应的任务中去调用 send(Response) 方法表明的含义是后者的功能从属于前者。这可能从业务角度上看是不合理的。即在本例中,responseFuture 所对应的任务和 send(Response) 方法在业务角度讲是属于同一级的。违反这一点会对代码可读性和可维护性不利。 + +## 创建 CompletableFuture + +以下四个静态方法用来为一段异步执行的代码创建 `CompletableFuture` 对象: + +```java +static CompletableFuture runAsync(Runnable runnable) +static CompletableFuture runAsync(Runnable runnable, Executor executor) +static CompletableFuture supplyAsync(Supplier supplier) +static CompletableFuture supplyAsync(Supplier supplier, Executor executor) +``` + +以 `Async` 结尾并且没有指定 `Executor` 的方法会使用 `ForkJoinPool.commonPool()` 作为它的线程池执行异步代码。 + +## 计算结果完成时的处理 + +当 `CompletableFuture` 的计算结果完成,或者抛出异常的时候,我们可以执行特定的 `Action`。 + +```javap +CompletableFuture whenComplete(BiConsumer action) +CompletableFuture whenCompleteAsync(BiConsumer action) +CompletableFuture whenCompleteAsync(BiConsumer action, Executor executor) +CompletableFuture exceptionally(Function fn) +``` + +同时进行计算和转换 + +```java + CompletableFuture handle(BiFunction fn) + CompletableFuture handleAsync(BiFunction fn) + CompletableFuture handleAsync(BiFunction fn, Executor executor) +``` + +## 结果转换(map) + +```java + CompletableFuture thenApply(Function fn) + CompletableFuture thenApplyAsync(Function fn) + CompletableFuture thenApplyAsync(Function fn, Executor executor) +``` + +## flatMap + +```java + CompletableFuture thenCompose(Function> fn) + CompletableFuture thenComposeAsync(Function> fn) + CompletableFuture thenComposeAsync(Function> fn, Executor executor) +``` + +## 消耗型 + +```java +CompletableFuture thenAccept(Consumer action) +CompletableFuture thenAcceptAsync(Consumer action) +CompletableFuture thenAcceptAsync(Consumer action, Executor executor) +``` + +`thenAccept(Consumer action)` 这个方法的命名采用了类似 Promise 的命名风格。 +如果把这个方法命名为 addListener 会更容易理解,但是命名为 addListener 不能体现出 thenAccept 能返回 CompletableFuture 从而形成链式调用的特点。 + +当两个 `CompletionStage` 都正常完成计算的时候,执行一个 `Runnable` + +```java + CompletableFuture thenAcceptBoth(CompletionStage other, BiConsumer action) + CompletableFuture thenAcceptBothAsync(CompletionStage other, BiConsumer action) + CompletableFuture thenAcceptBothAsync(CompletionStage other, BiConsumer action, Executor executor) + CompletableFuture runAfterBoth(CompletionStage other, Runnable action) +``` + +对上一步的计算结果不关心,执行下一个操作 + +```java +CompletableFuture thenRun(Runnable action) +CompletableFuture thenRunAsync(Runnable action) +CompletableFuture thenRunAsync(Runnable action, Executor executor) +``` + +## 组合 + +```java + CompletableFuture thenCombine(CompletionStage other, BiFunction fn) + CompletableFuture thenCombineAsync(CompletionStage other, BiFunction fn) + CompletableFuture thenCombineAsync(CompletionStage other, BiFunction fn, Executor executor) +``` + +## Either + +```java + CompletableFuture acceptEither(CompletionStage other, Consumer action) + CompletableFuture acceptEitherAsync(CompletionStage other, Consumer action) + CompletableFuture acceptEitherAsync(CompletionStage other, Consumer action, Executor executor) + CompletableFuture applyToEither(CompletionStage other, Function fn) + CompletableFuture applyToEitherAsync(CompletionStage other, Function fn) + CompletableFuture applyToEitherAsync(CompletionStage other, Function fn, Executor executor) +``` + +## allOf、anyOf + +```java +static CompletableFuture allOf(CompletableFuture... cfs) +static CompletableFuture anyOf(CompletableFuture... cfs) +``` + +[CompletableFuture 的 20 个例子](https://zhuanlan.zhihu.com/p/34921166) diff --git a/java8-completablefuture/pom.xml b/java8-completablefuture/pom.xml new file mode 100644 index 0000000..62b3144 --- /dev/null +++ b/java8-completablefuture/pom.xml @@ -0,0 +1,14 @@ + + + + learn-java8 + io.github.biezhi + 1.0-SNAPSHOT + + 4.0.0 + + java8-completablefuture + + \ No newline at end of file diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture1.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture1.java new file mode 100644 index 0000000..8c31b9c --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture1.java @@ -0,0 +1,19 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; + +/** + * 创建 CompletableFuture + * + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture1 { + + public static void main(String[] args) { + CompletableFuture helloFuture = CompletableFuture.runAsync(() -> System.out.println("hello future")); + + CompletableFuture integerCompletableFuture = CompletableFuture.supplyAsync(() -> 2333); + + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture10.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture10.java new file mode 100644 index 0000000..6c6a7a3 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture10.java @@ -0,0 +1,42 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture10 { + + private static CompletableFuture m1(){ + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return 2333; + }); + } + private static CompletableFuture m2(){ + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return 8877; + }); + } + + public static void main(String[] args) throws ExecutionException, InterruptedException { + long start = System.currentTimeMillis(); + CompletableFuture.anyOf(m1(), m2()) + .thenRun(() -> { + System.out.println(System.currentTimeMillis() - start); + }).get() + ; + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture2.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture2.java new file mode 100644 index 0000000..91b4e51 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture2.java @@ -0,0 +1,43 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * 处理计算结果 + * + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture2 { + + public static void main(String[] args) { + CompletableFuture uCompletableFuture = CompletableFuture.supplyAsync(() -> { + System.out.println("开始执行运算"); + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + int a = 1/0; + System.out.println("执行结束"); + return 2333; + }); + + try { + Integer result = uCompletableFuture.whenComplete((a, b) -> { + System.out.println("Result: " + a); + System.out.println("Exception: " + b); + }).exceptionally(e -> { + System.out.println(e.getMessage()); + return 666; + }).get(); + System.out.println(result); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture3.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture3.java new file mode 100644 index 0000000..5bbf46e --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture3.java @@ -0,0 +1,25 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; + +/** + * 结果转换 + * + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture3 { + + public static void main(String[] args) { + try { + String result = CompletableFuture.supplyAsync(() -> 2333) + .thenApply(String::valueOf).get(); + System.out.println(result); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture4.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture4.java new file mode 100644 index 0000000..85f093c --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture4.java @@ -0,0 +1,24 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 扁平转换 + * + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture4 { + + public static void main(String[] args) { + try { + String s = CompletableFuture.supplyAsync(() -> 23333) + .thenCompose(t -> CompletableFuture.supplyAsync(() -> t + "ddd")) + .get(); + System.out.println(s); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture5.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture5.java new file mode 100644 index 0000000..fdb1c7d --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture5.java @@ -0,0 +1,18 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 消费结果 + * + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture5 { + + public static void main(String[] args) throws ExecutionException, InterruptedException { + CompletableFuture.supplyAsync(() -> 9999) + .thenAccept(System.out::println).get(); + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture6.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture6.java new file mode 100644 index 0000000..11ba721 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture6.java @@ -0,0 +1,19 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture6 { + + public static void main(String[] args) throws ExecutionException, InterruptedException { + CompletableFuture.supplyAsync(() -> 9999) + .thenAcceptBoth(CompletableFuture.supplyAsync(() -> "7878"), (a, b) -> { + System.out.println("a = " + a); + System.out.println("b = " + b); + }).get(); + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture7.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture7.java new file mode 100644 index 0000000..a0c9009 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture7.java @@ -0,0 +1,26 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture7 { + + public static void main(String[] args) throws ExecutionException, InterruptedException { + CompletableFuture.supplyAsync(() -> { + try { + System.out.println("开始执行了"); + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return 9999; + }).thenRun(() -> { + System.out.println("执行结束了"); + }).get(); + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture8.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture8.java new file mode 100644 index 0000000..c0ccf33 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture8.java @@ -0,0 +1,28 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture8 { + + public static void main(String[] args) { + try { + String s = CompletableFuture.supplyAsync(() -> 23333) + .thenCombine(CompletableFuture.supplyAsync( () -> "8898" ), (a, b) -> { + System.out.println("a =" + a); + System.out.println("b =" + b); + return a + b; + }) + .get(); + System.out.println(s); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture9.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture9.java new file mode 100644 index 0000000..ce1e4e8 --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/CompletableFuture9.java @@ -0,0 +1,39 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class CompletableFuture9 { + + private static CompletableFuture m1(){ + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return 2333; + }); + } + private static CompletableFuture m2(){ + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return 8877; + }); + } + + public static void main(String[] args) throws ExecutionException, InterruptedException { + m1().acceptEither(m2(), t -> { + System.out.println("t = " + t); + }).get(); + } +} diff --git a/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/Future1.java b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/Future1.java new file mode 100644 index 0000000..b03353d --- /dev/null +++ b/java8-completablefuture/src/main/java/io/github/biezhi/java8/completablefuture/Future1.java @@ -0,0 +1,38 @@ +package io.github.biezhi.java8.completablefuture; + +import java.util.concurrent.*; + +/** + * @author biezhi + * @date 2018/3/25 + */ +public class Future1 { + + public static void main(String[] args) throws ExecutionException, InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(2); + + Future submit = executorService.submit(() -> { + TimeUnit.SECONDS.sleep(3); + return 100; + }); + +// try { +// Integer result = submit.get(); +// System.out.println(result); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } catch (ExecutionException e) { +// e.printStackTrace(); +// } + + while(!submit.isDone()){ + try { + TimeUnit.MILLISECONDS.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + Integer result = submit.get(); + System.out.println(result); + } +} diff --git a/java8-concurrent/README.md b/java8-concurrent/README.md new file mode 100644 index 0000000..e9a42ff --- /dev/null +++ b/java8-concurrent/README.md @@ -0,0 +1,311 @@ +# java8 concurrent + +1. [知乎专栏 - Threads和Executors](https://zhuanlan.zhihu.com/p/33266682) +2. [知乎专栏 - 同步和锁](http://zhuanlan.zhihu.com/p/33267015) +3. [知乎专栏 - 原子变量和 ConcurrentMap](https://zhuanlan.zhihu.com/p/33267165) + +## Thread 和 Runnable + +所有的现代操作系统都通过进程和线程来支持并发。进程是通常彼此独立运行的程序的实例,比如,如果你启动了一个Java程序,操作系统产生一个新的进程,与其他程序一起并行执行。 +在这些进程的内部,我们使用线程并发执行代码,因此,我们可以最大限度的利用CPU可用的核心(core)。 + +Java从JDK1.0开始执行线程。在开始一个新的线程之前,你必须指定由这个线程执行的代码,通常称为task。这可以通过实现Runnable——一个定义了一个无返回值无参数的 `run()` 方法的函数接口。 + +## 线程池 + +在执行一个异步任务或并发任务时,往往是通过直接 `new Thread()` 方法来创建新的线程,这样做弊端较多,更好的解决方案是合理地利用线程池,线程池的优势很明显,如下: + +1. 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗; +2. 提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行; +3. 方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率; +4. 更强大的功能,线程池提供了定时、定期以及可控线程数等功能的线程池,使用方便简单。 + +### 线程池用法 + +**newCachedThreadPool** + +创建一个可缓存的无界线程池,该方法无参数。当线程池中的线程空闲时间超过60s则会自动回收该线程,当任务超过线程池的线程数则创建新线程。线程池的大小上限为 `Integer.MAX_VALUE`,可看做是无限大。 + +```java +public void cachedThreadPoolDemo(){ + ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); + for (int i = 0; i < 5; i++) { + final int index = i; + + cachedThreadPool.execute(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName()+", index="+index); + } + }); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +``` + +运行结果: + +```bash +pool-1-thread-1, index=0 +pool-1-thread-1, index=1 +pool-1-thread-1, index=2 +pool-1-thread-1, index=3 +pool-1-thread-1, index=4 +``` + +从运行结果可以看出,整个过程都在同一个线程pool-1-thread-1中运行,后面线程复用前面的线程。 + +**newFixedThreadPool** + +创建一个固定大小的线程池,该方法可指定线程池的固定大小,对于超出的线程会在 `LinkedBlockingQueue` 队列中等待。 + +```java +public void fixedThreadPoolDemo(){ + ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); + for (int i = 0; i < 6; i++) { + final int index = i; + + fixedThreadPool.execute(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName()+", index="+index); + } + }); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +``` + +运行结果: + +```bash +pool-1-thread-1, index=0 +pool-1-thread-2, index=1 +pool-1-thread-3, index=2 +pool-1-thread-1, index=3 +pool-1-thread-2, index=4 +pool-1-thread-3, index=5 +``` + +从运行结果可以看出,线程池大小为3,每休眠1s后将任务提交给线程池的各个线程轮番交错地执行。线程池的大小设置,可参数 `Runtime.getRuntime().availableProcessors()`。 + +**newSingleThreadExecutor** + +创建一个只有线程的线程池,该方法无参数,所有任务都保存队列LinkedBlockingQueue中,等待唯一的单线程来执行任务,并保证所有任务按照指定顺序(FIFO或优先级)执行。 + +```java +public void singleThreadExecutorDemo(){ + ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); + for (int i = 0; i < 3; i++) { + final int index = i; + + singleThreadExecutor.execute(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName()+", index="+index); + } + }); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +``` + +运行结果: + +```bash +pool-1-thread-1, index=0 +pool-1-thread-1, index=1 +pool-1-thread-1, index=2 +``` + +从运行结果可以看出,所有任务都是在单一线程运行的。 + +**newScheduledThreadPool** + +创建一个可定时执行或周期执行任务的线程池,该方法可指定线程池的核心线程个数。 + +```java +public void scheduledThreadPoolDemo(){ + ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); + //定时执行一次的任务,延迟1s后执行 + scheduledThreadPool.schedule(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName()+", delay 1s"); + } + }, 1, TimeUnit.SECONDS); + + //周期性地执行任务,延迟2s后,每3s一次地周期性执行任务 + scheduledThreadPool.scheduleAtFixedRate(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName()+", every 3s"); + } + }, 2, 3, TimeUnit.SECONDS); +} +``` + +运行结果: + +```bash +pool-1-thread-1, delay 1s +pool-1-thread-1, every 3s +pool-1-thread-2, every 3s +pool-1-thread-2, every 3s +... +``` + +- `schedule(Runnable command, long delay, TimeUnit unit)`: 延迟一定时间后执行 `Runnable` 任务; +- `schedule(Callable callable, long delay, TimeUnit unit)`: 延迟一定时间后执行 `Callable` 任务; +- `scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)`: 延迟一定时间后,以间隔period时间的频率周期性地执行任务; +- `scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit)`: 与 `scheduleAtFixedRate()` 方法很类似, +但是不同的是scheduleWithFixedDelay()方法的周期时间间隔是以上一个任务执行结束到下一个任务开始执行的间隔, +而scheduleAtFixedRate()方法的周期时间间隔是以上一个任务开始执行到下一个任务开始执行的间隔,也就是这一些任务系列的触发时间都是可预知的。 + +> ScheduledExecutorService 功能强大,对于定时执行的任务,建议多采用该方法。 + +**方法对比** + +| 工厂方法 | corePoolSize | maximumPoolSize | keepAliveTime | workQueue | +|:-----:|:--------|:-------|:-------|:-------| +| `newCachedThreadPool` | 0 | Integer.MAX_VALUE | 60s `SynchronousQueue` | +| `newFixedThreadPool` | nThreads | nThreads | 0 | `LinkedBlockingQueue` | +| `newSingleThreadExecutor` | 1 | 1 | 0 | `LinkedBlockingQueue` | +| `newScheduledThreadPool` | corePoolSize | Integer.MAX_VALUE | 0 | `DelayedWorkQueue` | + +其他参数都相同,其中线程工厂的默认类为 `DefaultThreadFactory`,线程饱和的默认策略为 `ThreadPoolExecutor.AbortPolicy`。 + +## 简单使用 Lock 锁 + +Java 5 中引入了新的锁机制——java.util.concurrent.locks 中的显式的互斥锁:Lock 接口,它提供了比 `synchronized` 更加广泛的锁定操作。 +Lock 接口有 3 个实现它的类:ReentrantLock、ReetrantReadWriteLock.ReadLock 和 ReetrantReadWriteLock.WriteLock,即重入锁、读锁和写锁。 +lock 必须被显式地创建、锁定和释放,为了可以使用更多的功能,一般用 ReentrantLock 为其实例化。为了保证锁最终一定会被释放(可能会有异常发生),要把互斥区放在 try 语句块内,并在 finally 语句块中释放锁,尤其当有 return 语句时,return 语句必须放在 try 字句中,以确保 unlock()不会过早发生,从而将数据暴露给第二个任务。因此,采用 lock 加锁和释放锁的一般形式如下: + +```java +//默认使用非公平锁,如果要使用公平锁,需要传入参数true +Lock lock = new ReentrantLock(); +lock.lock(); +try { + // 更新对象的状态 + // 捕获异常,必要时恢复到原来的不变约束 + // 如果有return语句,放在这里 +} finally { + //锁必须在finally块中释放 + lock.unlock(); +} +``` + +可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响。 +在JAVA环境下 `ReentrantLock` 和 `synchronized` 都是可重入锁。 + +**ReentrantReadWriteLock** + +读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。 +如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。 +总之,读的时候上读锁,写的时候上写锁! + +`ReentrantReadWriteLock` 会使用两把锁来解决问题,一个读锁,一个写锁 + +- 线程进入读锁的前提条件 + - 没有其他线程的写锁 + - 没有写请求或者有写请求,但调用线程和持有锁的线程是同一个 +- 线程进入写锁的前提条件 + - 没有其他线程的读锁 + - 没有其他线程的写锁 + +## StampedLock + +`StampedLock` 是 java 8 在 `java.util.concurrent.locks` 新增的一个API。 + +`ReentrantReadWriteLock` 在沒有任何读锁和写锁时,才可以取得写入锁,这可用于实现了悲观读取。 +然而,如果读取很多,写入很少的情况下,使用 `ReentrantReadWriteLock` 可能会使写入线程遭遇饥饿问题,也就是写入线程无法竞争到锁定而一直处于等待状态。 +`StampedLock` 有三种模式的锁,用于控制读取/写入访问,StampedLock 的状态由版本和模式组成。 +锁获取操作返回一个用于展示和访问锁状态的票据(stamp)变量,它用相应的锁状态表示并控制访问,数字0表示没有写锁被授权访问。 +在读锁上分为悲观锁和乐观锁,锁释放以及其他相关方法需要使用邮戳(stamps)变量作为参数,如果他们和当前锁状态不符则失败,这三种模式为: + +- 写入:方法writeLock可能为了获取独占访问而阻塞当前线程,返回一个stamp变量,能够在unlockWrite方法中使用从而释放锁。也提供了tryWriteLock。 +当锁被写模式所占有,没有读或者乐观的读操作能够成功。 +- 读取:方法readLock可能为了获取非独占访问而阻塞当前线程,返回一个stamp变量,能够在unlockRead方法中用于释放锁。也提供了tryReadLock。 +- 乐观读取:方法 `tryOptimisticRead` 返回一个非 0 邮戳变量,仅在当前锁没有以写入模式被持有。如果在获得stamp变量之后没有被写模式持有,方法validate将返回true。 +这种模式可以被看做一种弱版本的读锁,可以被一个写入者在任何时间打断。乐观读取模式仅用于短时间读取操作时经常能够降低竞争和提高吞吐量。 + +> 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。 +> 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。 +> Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。 + +> 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。 +乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。 +> 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 + +## AtomicInteger + +JDK1.5之后的java.util.concurrent.atomic包里,多了一批原子处理类。 +AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。 +主要用于在高并发环境下的高效程序处理,来帮助我们简化同步处理. + +AtomicInteger,一个提供原子操作的Integer的类。 +在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。 +而AtomicInteger则通过一种线程安全的加减操作接口。 + +```java +public final int get() //获取当前的值 +public final int getAndSet(int newValue)//获取当前的值,并设置新的值 +public final int getAndIncrement() //获取当前的值,并自增 +public final int getAndDecrement() //获取当前的值,并自减 +public final int getAndAdd(int delta) //获取当前的值,并加上预期的值 +``` + +## LongAccumulator + +`LongAdder` 是jdk1.8提供的累加器,基于 `Striped64` 实现。 +它常用于状态采集、统计等场景。 +AtomicLong也可以用于这种场景,但在线程竞争激烈的情况下,LongAdder要比AtomicLong拥有更高的吞吐量,但会耗费更多的内存空间。 + +`LongAccumulator` 和 `LongAdder` 类似,也基于Striped64实现。但要比LongAdder更加灵活(要传入一个函数接口), +LongAdder相当于是LongAccumulator的一种特例。 + +## Semaphore + +Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。 +很多年以来,我都觉得从字面上很难理解Semaphore所表达的含义,只能把它比作是控制流量的红绿灯,比如XX马路要限制流量,只允许同时有一百辆车在这条路上行使, +其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入XX马路, +但是如果前一百辆中有五辆车已经离开了XX马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行, +离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。 + +**应用场景** + +Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。 +假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取, +但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个, +这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。 +这个时候,我们就可以使用Semaphore来做流控。 + +## 参考资料 + +- [Java线程池分析](http://gityuan.com/2016/01/16/thread-pool/) +- [浅谈Java中的锁](http://zhwbqd.github.io/2015/02/13/lock-in-java.html) +- [Java原子操作AtomicInteger的用法](https://www.jianshu.com/p/509aca840f6d) +- [Jdk1.8 JUC源码增量解析 LongAdder和LongAccumulator](http://brokendreams.iteye.com/blog/2259858) +- [StampedLock将是解决同步问题的新宠](http://www.importnew.com/14941.html) +- [Java8 StampedLock](https://coderbee.net/index.php/concurrent/20140628/947) +- [控制并发线程数的Semaphore](http://ifeve.com/tag/semaphore/) \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Atomic1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Atomic1.java new file mode 100644 index 0000000..712c8fa --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Atomic1.java @@ -0,0 +1,76 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +/** + * 原子变量 + *

+ * AtomicInteger + * LongAdder + * LongAccumulator + * + * @author biezhi + * @date 2018/3/5 + */ +public class Atomic1 { + + private static final int NUM_INCREMENTS = 1000; + + private static AtomicInteger atomicInt = new AtomicInteger(0); + + public static void main(String[] args) { + testIncrement(); +// testAccumulate(); +// testUpdate(); + } + + private static void testUpdate() { + atomicInt.set(0); + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> { + Runnable task = () -> + atomicInt.updateAndGet(n -> n + 2); + executor.submit(task); + }); + + ConcurrentUtils.stop(executor); + + System.out.format("Update: %d\n", atomicInt.get()); + } + + private static void testAccumulate() { + atomicInt.set(0); + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> { + Runnable task = () -> + atomicInt.accumulateAndGet(i, (n, m) -> n + m); + executor.submit(task); + }); + + ConcurrentUtils.stop(executor); + + System.out.format("Accumulate: %d\n", atomicInt.get()); + } + + private static void testIncrement() { + atomicInt.set(0); + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(atomicInt::incrementAndGet)); + + ConcurrentUtils.stop(executor); + + System.out.format("Increment: Expected=%d; Is=%d\n", NUM_INCREMENTS, atomicInt.get()); + } +} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/AtomicExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/AtomicExample.java deleted file mode 100644 index b08c71f..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/AtomicExample.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; - -/** - * 原子变量 - *

- * AtomicInteger - * LongAdder - * LongAccumulator - * - * @author biezhi - * @date 2018/3/5 - */ -public class AtomicExample { - - public static void main(String[] args) { - AtomicInteger atomicInt = new AtomicInteger(0); - ExecutorService executor = Executors.newFixedThreadPool(2); - IntStream.range(0, 1000) - .forEach(i -> executor.submit(atomicInt::incrementAndGet)); - stop(executor); - System.out.println(atomicInt.get()); - } - - public static void stop(ExecutorService executor) { - try { - System.out.println("attempt to shutdown executor"); - executor.shutdown(); - executor.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - System.err.println("tasks interrupted"); - } finally { - if (!executor.isTerminated()) { - System.err.println("cancel non-finished tasks"); - } - executor.shutdownNow(); - System.out.println("shutdown finished"); - } - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/CallableExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/CallableExample.java deleted file mode 100644 index 5231d8a..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/CallableExample.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.*; - -/** - * Callable Future - * - * @author biezhi - * @date 2018/3/5 - */ -public class CallableExample { - - public static void main(String[] args) throws ExecutionException, InterruptedException { - Callable task = () -> { - try { - TimeUnit.MINUTES.sleep(1); - return 123; - } catch (InterruptedException e) { - throw new IllegalStateException("task interrupted", e); - } - }; - - ExecutorService executor = Executors.newFixedThreadPool(1); - Future future = executor.submit(task); - System.out.println("future done? " + future.isDone()); - Integer result = future.get(); - System.out.println("future done? " + future.isDone()); - System.out.print("result: " + result); - - } -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentHashMap1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentHashMap1.java new file mode 100644 index 0000000..3265838 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentHashMap1.java @@ -0,0 +1,74 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; + +public class ConcurrentHashMap1 { + + public static void main(String[] args) { + System.out.println("Parallelism: " + ForkJoinPool.getCommonPoolParallelism()); + + testForEach(); +// testSearch(); +// testReduce(); + } + + private static void testReduce() { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.putIfAbsent("foo", "bar"); + map.putIfAbsent("han", "solo"); + map.putIfAbsent("r2", "d2"); + map.putIfAbsent("c3", "p0"); + + String reduced = map.reduce(1, (key, value) -> key + "=" + value, + (s1, s2) -> s1 + ", " + s2); + + System.out.println(reduced); + } + + private static void testSearch() { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.putIfAbsent("foo", "bar"); + map.putIfAbsent("han", "solo"); + map.putIfAbsent("r2", "d2"); + map.putIfAbsent("c3", "p0"); + + System.out.println("\nsearch()\n"); + + String result1 = map.search(1, (key, value) -> { + System.out.println(Thread.currentThread().getName()); + if (key.equals("foo") && value.equals("bar")) { + return "foobar"; + } + return null; + }); + + System.out.println(result1); + + System.out.println("\nsearchValues()\n"); + + String result2 = map.searchValues(1, value -> { + System.out.println(Thread.currentThread().getName()); + if (value.length() > 3) { + return value; + } + return null; + }); + + System.out.println(result2); + } + + private static void testForEach() { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.putIfAbsent("foo", "bar"); + map.putIfAbsent("han", "solo"); + map.putIfAbsent("r2", "d2"); + map.putIfAbsent("c3", "p0"); + + map.forEach(1, (key, value) -> System.out.printf("key: %s; value: %s; thread: %s\n", key, value, Thread.currentThread().getName())); +// map.forEach(5, (key, value) -> System.out.printf("key: %s; value: %s; thread: %s\n", key, value, Thread.currentThread().getName())); + + System.out.println(map.mappingCount()); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentMapExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentMapExample.java deleted file mode 100644 index 6f81aa2..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentMapExample.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * ConcurrentMap - *

- * forEach - * putIfAbsent - * getOrDefault - * replaceAll - * compute - * merge - * search - * reduce - * - * @author biezhi - * @date 2018/3/5 - */ -public class ConcurrentMapExample { - - public static void main(String[] args) { - ConcurrentMap map = new ConcurrentHashMap<>(); - map.put("foo", "bar"); - map.put("han", "solo"); - map.put("r2", "d2"); - map.put("c3", "p0"); - - map.forEach((key, value) -> System.out.printf("%s = %s\n", key, value)); - - } -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentUtils.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentUtils.java new file mode 100644 index 0000000..f95c1f1 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ConcurrentUtils.java @@ -0,0 +1,39 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 并发工具类 + * + * @author biezhi + * @date 2018/3/11 + */ +public class ConcurrentUtils { + + public static void stop(ExecutorService executor) { + try { + executor.shutdown(); + executor.awaitTermination(60, TimeUnit.SECONDS); + } + catch (InterruptedException e) { + System.err.println("termination interrupted"); + } + finally { + if (!executor.isTerminated()) { + System.err.println("killing non-finished tasks"); + } + executor.shutdownNow(); + } + } + + public static void sleep(int seconds) { + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + } + + +} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ExecutorExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ExecutorExample.java deleted file mode 100644 index 8e6ef79..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ExecutorExample.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * 执行器 - * - * @author biezhi - * @date 2018/3/5 - */ -public class ExecutorExample { - - public static void main(String[] args) { - ExecutorService executor = Executors.newSingleThreadExecutor(); - executor.submit(() -> { - String threadName = Thread.currentThread().getName(); - System.out.println("Hello " + threadName); - }); - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors1.java new file mode 100644 index 0000000..c3ae935 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors1.java @@ -0,0 +1,43 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class Executors1 { + + public static void main(String[] args) { + test1(3); +// test1(7); + } + + private static void test1(long seconds) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.submit(() -> { + try { + TimeUnit.SECONDS.sleep(seconds); + String name = Thread.currentThread().getName(); + System.out.println("task finished: " + name); + } catch (InterruptedException e) { + System.err.println("task interrupted"); + } + }); + stop(executor); + } + + static void stop(ExecutorService executor) { + try { + System.out.println("attempt to shutdown executor"); + executor.shutdown(); + executor.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + System.err.println("termination interrupted"); + } finally { + if (!executor.isTerminated()) { + System.err.println("killing non-finished tasks"); + } + executor.shutdownNow(); + System.out.println("shutdown finished"); + } + } +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors2.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors2.java new file mode 100644 index 0000000..e90ecd2 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors2.java @@ -0,0 +1,66 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.*; + +public class Executors2 { + + public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException { + test1(); +// test2(); +// test3(); + } + + private static void test3() throws InterruptedException, ExecutionException, TimeoutException { + ExecutorService executor = Executors.newFixedThreadPool(1); + + Future future = executor.submit(() -> { + try { + TimeUnit.SECONDS.sleep(2); + return 123; + } catch (InterruptedException e) { + throw new IllegalStateException("task interrupted", e); + } + }); + + future.get(1, TimeUnit.SECONDS); + } + + private static void test2() throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newFixedThreadPool(1); + + Future future = executor.submit(() -> { + try { + TimeUnit.SECONDS.sleep(1); + return 123; + } catch (InterruptedException e) { + throw new IllegalStateException("task interrupted", e); + } + }); + + executor.shutdownNow(); + future.get(); + } + + private static void test1() throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newFixedThreadPool(1); + + Future future = executor.submit(() -> { + try { + TimeUnit.SECONDS.sleep(1); + return 123; + } catch (InterruptedException e) { + throw new IllegalStateException("task interrupted", e); + } + }); + + System.out.println("future done: " + future.isDone()); + + Integer result = future.get(); + + System.out.println("future done: " + future.isDone()); + System.out.print("result: " + result); + + executor.shutdownNow(); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors3.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors3.java new file mode 100644 index 0000000..155d665 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Executors3.java @@ -0,0 +1,97 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.*; + +public class Executors3 { + + public static void main(String[] args) throws InterruptedException, ExecutionException { + test1(); +// test2(); +// test3(); + +// test4(); +// test5(); + } + + private static void test5() throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newWorkStealingPool(); + + List> callables = Arrays.asList( + callable("task1", 2), + callable("task2", 1), + callable("task3", 3)); + + String result = executor.invokeAny(callables); + System.out.println(result); + + executor.shutdown(); + } + + private static Callable callable(String result, long sleepSeconds) { + return () -> { + TimeUnit.SECONDS.sleep(sleepSeconds); + return result; + }; + } + + private static void test4() throws InterruptedException { + ExecutorService executor = Executors.newWorkStealingPool(); + + List> callables = Arrays.asList( + () -> "task1", + () -> "task2", + () -> "task3"); + + executor.invokeAll(callables) + .stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }) + .forEach(System.out::println); + + executor.shutdown(); + } + + private static void test3() { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + + Runnable task = () -> { + try { + TimeUnit.SECONDS.sleep(2); + System.out.println("Scheduling: " + System.nanoTime()); + } catch (InterruptedException e) { + System.err.println("task interrupted"); + } + }; + + executor.scheduleWithFixedDelay(task, 0, 1, TimeUnit.SECONDS); + } + + private static void test2() { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + Runnable task = () -> System.out.println("Scheduling: " + System.nanoTime()); + int initialDelay = 0; + int period = 1; + executor.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS); + } + + private static void test1() throws InterruptedException { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + + Runnable task = () -> System.out.println("Scheduling: " + System.nanoTime()); + int delay = 3; + ScheduledFuture future = executor.schedule(task, delay, TimeUnit.SECONDS); + + TimeUnit.MILLISECONDS.sleep(1337); + + long remainingDelay = future.getDelay(TimeUnit.MILLISECONDS); + System.out.printf("Remaining Delay: %sms\n", remainingDelay); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock1.java new file mode 100644 index 0000000..631daae --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock1.java @@ -0,0 +1,42 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.IntStream; + +public class Lock1 { + + private static final int NUM_INCREMENTS = 10000; + + private static ReentrantLock lock = new ReentrantLock(); + + private static int count = 0; + + private static void increment() { + lock.lock(); + try { + count++; + } finally { + lock.unlock(); + } + } + + public static void main(String[] args) { + testLock(); + } + + private static void testLock() { + count = 0; + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(Lock1::increment)); + + ConcurrentUtils.stop(executor); + + System.out.println(count); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock2.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock2.java new file mode 100644 index 0000000..f5dffa9 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock2.java @@ -0,0 +1,33 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; + +public class Lock2 { + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(2); + + ReentrantLock lock = new ReentrantLock(); + + executor.submit(() -> { + lock.lock(); + try { + ConcurrentUtils.sleep(1); + } finally { + lock.unlock(); + } + }); + + executor.submit(() -> { + System.out.println("Locked: " + lock.isLocked()); + System.out.println("Held by me: " + lock.isHeldByCurrentThread()); + boolean locked = lock.tryLock(); + System.out.println("Lock acquired: " + locked); + }); + + ConcurrentUtils.stop(executor); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock3.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock3.java new file mode 100644 index 0000000..e0e47fa --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock3.java @@ -0,0 +1,44 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class Lock3 { + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(2); + + Map map = new HashMap<>(); + + ReadWriteLock lock = new ReentrantReadWriteLock(); + + executor.submit(() -> { + lock.writeLock().lock(); + try { + ConcurrentUtils.sleep(1); + map.put("foo", "bar"); + } finally { + lock.writeLock().unlock(); + } + }); + + Runnable readTask = () -> { + lock.readLock().lock(); + try { + System.out.println(map.get("foo")); + ConcurrentUtils.sleep(1); + } finally { + lock.readLock().unlock(); + } + }; + executor.submit(readTask); + executor.submit(readTask); + + ConcurrentUtils.stop(executor); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock4.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock4.java new file mode 100644 index 0000000..6e933b5 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock4.java @@ -0,0 +1,43 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.StampedLock; + +public class Lock4 { + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(2); + + Map map = new HashMap<>(); + + StampedLock lock = new StampedLock(); + + executor.submit(() -> { + long stamp = lock.writeLock(); + try { + ConcurrentUtils.sleep(1); + map.put("foo", "bar"); + } finally { + lock.unlockWrite(stamp); + } + }); + + Runnable readTask = () -> { + long stamp = lock.readLock(); + try { + System.out.println(map.get("foo")); + ConcurrentUtils.sleep(1); + } finally { + lock.unlockRead(stamp); + } + }; + executor.submit(readTask); + executor.submit(readTask); + + ConcurrentUtils.stop(executor); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock5.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock5.java new file mode 100644 index 0000000..b78a6fd --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock5.java @@ -0,0 +1,41 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.StampedLock; + +public class Lock5 { + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(2); + + StampedLock lock = new StampedLock(); + + executor.submit(() -> { + long stamp = lock.tryOptimisticRead(); + try { + System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); + ConcurrentUtils.sleep(1); + System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); + ConcurrentUtils.sleep(2); + System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); + } finally { + lock.unlock(stamp); + } + }); + + executor.submit(() -> { + long stamp = lock.writeLock(); + try { + System.out.println("Write Lock acquired"); + ConcurrentUtils.sleep(2); + } finally { + lock.unlock(stamp); + System.out.println("Write done"); + } + }); + + ConcurrentUtils.stop(executor); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock6.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock6.java new file mode 100644 index 0000000..af7977f --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Lock6.java @@ -0,0 +1,36 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.StampedLock; + +public class Lock6 { + + private static int count = 0; + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(2); + + StampedLock lock = new StampedLock(); + + executor.submit(() -> { + long stamp = lock.readLock(); + try { + if (count == 0) { + stamp = lock.tryConvertToWriteLock(stamp); + if (stamp == 0L) { + System.out.println("Could not convert to write lock"); + stamp = lock.writeLock(); + } + count = 23; + } + System.out.println(count); + } finally { + lock.unlock(stamp); + } + }); + + ConcurrentUtils.stop(executor); + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LockExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LockExample.java deleted file mode 100644 index b1fb075..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LockExample.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; - -import static java.lang.Thread.sleep; - -/** - * 锁 - *

- * ReentrantLock - * ReadWriteLock - * StampedLock - * - * @author biezhi - * @date 2018/3/5 - */ -public class LockExample { - - ReentrantLock lock = new ReentrantLock(); - - int count = 0; - - private void increment() { - lock.lock(); - try { - count++; - } finally { - lock.unlock(); - } - } - - public void start() { - ExecutorService executor = Executors.newFixedThreadPool(2); - executor.submit(() -> { - lock.lock(); - try { - sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - }); - executor.submit(() -> { - System.out.println("Locked: " + lock.isLocked()); - System.out.println("Held by me: " + lock.isHeldByCurrentThread()); - boolean locked = lock.tryLock(); - System.out.println("Lock acquired: " + locked); - }); - stop(executor); - } - - public static void main(String[] args) { - new LockExample().start(); - } - - public void stop(ExecutorService executor) { - try { - System.out.println("attempt to shutdown executor"); - executor.shutdown(); - executor.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - System.err.println("tasks interrupted"); - } finally { - if (!executor.isTerminated()) { - System.err.println("cancel non-finished tasks"); - } - executor.shutdownNow(); - System.out.println("shutdown finished"); - } - } -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAccumulator1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAccumulator1.java new file mode 100644 index 0000000..2aac7e4 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAccumulator1.java @@ -0,0 +1,28 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.LongAccumulator; +import java.util.function.LongBinaryOperator; +import java.util.stream.IntStream; + +public class LongAccumulator1 { + + public static void main(String[] args) { + testAccumulate(); + } + + private static void testAccumulate() { + LongBinaryOperator op = (x, y) -> 2 * x + y; + LongAccumulator accumulator = new LongAccumulator(op, 1L); + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, 10) + .forEach(i -> executor.submit(() -> accumulator.accumulate(i))); + + ConcurrentUtils.stop(executor); + + System.out.format("Add: %d\n", accumulator.getThenReset()); + } +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAdder1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAdder1.java new file mode 100644 index 0000000..a031154 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/LongAdder1.java @@ -0,0 +1,40 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.LongAdder; +import java.util.stream.IntStream; + +public class LongAdder1 { + + private static final int NUM_INCREMENTS = 10000; + + private static LongAdder adder = new LongAdder(); + + public static void main(String[] args) { + testIncrement(); + testAdd(); + } + + private static void testAdd() { + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(() -> adder.add(2))); + + ConcurrentUtils.stop(executor); + + System.out.format("Add: %d\n", adder.sumThenReset()); + } + + private static void testIncrement() { + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(adder::increment)); + + ConcurrentUtils.stop(executor); + + System.out.format("Increment: Expected=%d; Is=%d\n", NUM_INCREMENTS, adder.sumThenReset()); + } +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ScheduledExecutorExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ScheduledExecutorExample.java deleted file mode 100644 index 6f29b57..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ScheduledExecutorExample.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -/** - * ScheduledExecutor - * - * @author biezhi - * @date 2018/3/5 - */ -public class ScheduledExecutorExample { - - public static void main(String[] args) throws InterruptedException { - ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - Runnable task = () -> System.out.println("Scheduling: " + System.nanoTime()); - ScheduledFuture future = executor.schedule(task, 3, TimeUnit.SECONDS); - TimeUnit.MILLISECONDS.sleep(1337); - long remainingDelay = future.getDelay(TimeUnit.MILLISECONDS); - System.out.printf("剩余延迟: %sms", remainingDelay); - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore1.java new file mode 100644 index 0000000..edcf297 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore1.java @@ -0,0 +1,46 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class Semaphore1 { + + private static final int NUM_INCREMENTS = 10000; + + private static Semaphore semaphore = new Semaphore(1); + + private static int count = 0; + + public static void main(String[] args) { + testIncrement(); + } + + private static void testIncrement() { + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(Semaphore1::increment)); + + ConcurrentUtils.stop(executor); + + System.out.println("Increment: " + count); + } + + private static void increment() { + boolean permit = false; + try { + permit = semaphore.tryAcquire(5, TimeUnit.SECONDS); + count++; + } catch (InterruptedException e) { + throw new RuntimeException("could not increment"); + } finally { + if (permit) { + semaphore.release(); + } + } + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore2.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore2.java new file mode 100644 index 0000000..2dcbb74 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Semaphore2.java @@ -0,0 +1,41 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class Semaphore2 { + + private static Semaphore semaphore = new Semaphore(5); + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(10); + + IntStream.range(0, 10) + .forEach(i -> executor.submit(Semaphore2::doWork)); + + ConcurrentUtils.stop(executor); + } + + private static void doWork() { + boolean permit = false; + try { + permit = semaphore.tryAcquire(1, TimeUnit.SECONDS); + if (permit) { + System.out.println("Semaphore acquired"); + ConcurrentUtils.sleep(5); + } else { + System.out.println("Could not acquire semaphore"); + } + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } finally { + if (permit) { + semaphore.release(); + } + } + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SemaphoreExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SemaphoreExample.java deleted file mode 100644 index dcda166..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SemaphoreExample.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; - -import static java.lang.Thread.sleep; - -/** - * 信号量 - *

- * Semaphore - * - * @author biezhi - * @date 2018/3/5 - */ -public class SemaphoreExample { - - public static void main(String[] args) { - ExecutorService executor = Executors.newFixedThreadPool(10); - Semaphore semaphore = new Semaphore(5); - Runnable longRunningTask = () -> { - boolean permit = false; - try { - permit = semaphore.tryAcquire(1, TimeUnit.SECONDS); - if (permit) { - System.out.println("Semaphore acquired"); - sleep(5); - } else { - System.out.println("Could not acquire semaphore"); - } - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } finally { - if (permit) { - semaphore.release(); - } - } - }; - - IntStream.range(0, 10) - .forEach(i -> executor.submit(longRunningTask)); - stop(executor); - } - - public static void stop(ExecutorService executor) { - try { - System.out.println("attempt to shutdown executor"); - executor.shutdown(); - executor.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - System.err.println("tasks interrupted"); - } finally { - if (!executor.isTerminated()) { - System.err.println("cancel non-finished tasks"); - } - executor.shutdownNow(); - System.out.println("shutdown finished"); - } - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SynchronizeExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SynchronizeExample.java deleted file mode 100644 index 010ea4a..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/SynchronizeExample.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; - -/** - * 同步 - * - * @author biezhi - * @date 2018/3/5 - */ -public class SynchronizeExample { - - int count = 0; - - private void increment() { - count = count + 1; - } - - public void start() { - ExecutorService executor = Executors.newFixedThreadPool(2); - IntStream.range(0, 10000) - .forEach(i -> executor.submit(this::increment)); - stop(executor); - System.out.println(count); // 9965 - } - - public static void main(String[] args) { - new SynchronizeExample().start(); - } - - public void stop(ExecutorService executor) { - try { - System.out.println("attempt to shutdown executor"); - executor.shutdown(); - executor.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - System.err.println("tasks interrupted"); - } finally { - if (!executor.isTerminated()) { - System.err.println("cancel non-finished tasks"); - } - executor.shutdownNow(); - System.out.println("shutdown finished"); - } - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized1.java new file mode 100644 index 0000000..6894030 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized1.java @@ -0,0 +1,52 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.IntStream; + +public class Synchronized1 { + + private static final int NUM_INCREMENTS = 10000; + + private static int count = 0; + + public static void main(String[] args) { + testSyncIncrement(); + testNonSyncIncrement(); + } + + private static void testSyncIncrement() { + count = 0; + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(Synchronized1::incrementSync)); + + ConcurrentUtils.stop(executor); + + System.out.println(" Sync: " + count); + } + + private static void testNonSyncIncrement() { + count = 0; + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(Synchronized1::increment)); + + ConcurrentUtils.stop(executor); + + System.out.println("NonSync: " + count); + } + + private static synchronized void incrementSync() { + count = count + 1; + } + + private static void increment() { + count = count + 1; + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized2.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized2.java new file mode 100644 index 0000000..27e9613 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Synchronized2.java @@ -0,0 +1,36 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.IntStream; + +public class Synchronized2 { + + private static final int NUM_INCREMENTS = 10000; + + private static int count = 0; + + public static void main(String[] args) { + testSyncIncrement(); + } + + private static void testSyncIncrement() { + count = 0; + + ExecutorService executor = Executors.newFixedThreadPool(2); + + IntStream.range(0, NUM_INCREMENTS) + .forEach(i -> executor.submit(Synchronized2::incrementSync)); + + ConcurrentUtils.stop(executor); + + System.out.println(count); + } + + private static void incrementSync() { + synchronized (Synchronized2.class) { + count = count + 1; + } + } + +} \ No newline at end of file diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ThreadExample.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ThreadExample.java deleted file mode 100644 index 116f88f..0000000 --- a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/ThreadExample.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.biezhi.java8.concurrent; - -/** - * 线程 - * - * @author biezhi - * @date 2018/3/5 - */ -public class ThreadExample { - - public static void main(String[] args) { - Runnable task = () -> { - String threadName = Thread.currentThread().getName(); - System.out.println("Hello " + threadName); - }; - task.run(); - Thread thread = new Thread(task); - thread.start(); - System.out.println("Done!"); - } - -} diff --git a/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Threads1.java b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Threads1.java new file mode 100644 index 0000000..c3f9bd5 --- /dev/null +++ b/java8-concurrent/src/main/java/io/github/biezhi/java8/concurrent/Threads1.java @@ -0,0 +1,58 @@ +package io.github.biezhi.java8.concurrent; + +import java.util.concurrent.TimeUnit; + +public class Threads1 { + + public static void main(String[] args) { + test1(); +// test2(); +// test3(); + } + + private static void test3() { + Runnable runnable = () -> { + try { + System.out.println("Foo " + Thread.currentThread().getName()); + TimeUnit.SECONDS.sleep(1); + System.out.println("Bar " + Thread.currentThread().getName()); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + }; + + Thread thread = new Thread(runnable); + thread.start(); + } + + private static void test2() { + Runnable runnable = () -> { + try { + System.out.println("Foo " + Thread.currentThread().getName()); + Thread.sleep(1000); + System.out.println("Bar " + Thread.currentThread().getName()); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + }; + + Thread thread = new Thread(runnable); + thread.start(); + } + + private static void test1() { + Runnable runnable = () -> { + String threadName = Thread.currentThread().getName(); + System.out.println("Hello " + threadName); + }; + + runnable.run(); + + Thread thread = new Thread(runnable); + thread.start(); + + System.out.println("Done!"); + } +} \ No newline at end of file diff --git a/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson1/FilterProjects.java b/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson1/FilterProjects.java index abd7e1a..3c803b6 100644 --- a/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson1/FilterProjects.java +++ b/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson1/FilterProjects.java @@ -68,7 +68,7 @@ public static List filterLanguageAndStarProjects(List projects } /** - * 按照谓词条件过滤 + * 按照断言条件过滤 * * @param projects * @param projectPredicate diff --git a/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson2/FunctionalDemo.java b/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson2/FunctionalDemo.java index 211bed1..23e4498 100644 --- a/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson2/FunctionalDemo.java +++ b/java8-lambda/src/main/java/io/github/biezhi/java8/lambda/lesson2/FunctionalDemo.java @@ -36,7 +36,7 @@ public void consumer() { */ public void function() { Function toUpperCase = name -> name.toUpperCase(); - toUpperCase.apply("java"); // Java + toUpperCase.apply("Java"); // Java } /** diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn1.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn1.java new file mode 100644 index 0000000..170dd94 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn1.java @@ -0,0 +1,31 @@ +package io.github.biezhi.java8.nashorn; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.io.FileReader; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * Calling javascript functions from java with nashorn. + * + * @author Benjamin Winterberg + */ +public class Nashorn1 { + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval(new FileReader("java8-nashorn/src/main/resources/nashorn1.js")); + + Invocable invocable = (Invocable) engine; + Object result = invocable.invokeFunction("fun1", "Peter Parker"); + System.out.println(result); + System.out.println(result.getClass()); + + invocable.invokeFunction("fun2", new Date()); + invocable.invokeFunction("fun2", LocalDateTime.now()); + invocable.invokeFunction("fun2", new Person()); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn10.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn10.java new file mode 100644 index 0000000..71eafe2 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn10.java @@ -0,0 +1,27 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.concurrent.TimeUnit; + +/** + * @author Benjamin Winterberg + */ +public class Nashorn10 { + + public static void main(String[] args) throws ScriptException, NoSuchMethodException { + NashornScriptEngine engine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn10.js')"); + + long t0 = System.nanoTime(); + + for (int i = 0; i < 100000; i++) { + engine.invokeFunction("testPerf"); + } + + long took = System.nanoTime() - t0; + System.out.format("Elapsed time: %d ms", TimeUnit.NANOSECONDS.toMillis(took)); + } +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn11.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn11.java new file mode 100644 index 0000000..2ef3d56 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn11.java @@ -0,0 +1,157 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import javax.script.SimpleBindings; +import javax.script.SimpleScriptContext; + +/** + * @author Benjamin Winterberg + */ +public class Nashorn11 { + + public static void main(String[] args) throws Exception { +// test1(); +// test2(); +// test3(); +// test4(); +// test5(); +// test6(); +// test7(); + test8(); + } + + private static void test8() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + engine.eval("var obj = { foo: 23 };"); + + ScriptContext defaultContext = engine.getContext(); + Bindings defaultBindings = defaultContext.getBindings(ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context1 = new SimpleScriptContext(); + context1.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context2 = new SimpleScriptContext(); + context2.getBindings(ScriptContext.ENGINE_SCOPE).put("obj", defaultBindings.get("obj")); + + engine.eval("obj.foo = 44;", context1); + engine.eval("print(obj.foo);", context1); + engine.eval("print(obj.foo);", context2); + } + + private static void test7() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + engine.eval("var foo = 23;"); + + ScriptContext defaultContext = engine.getContext(); + Bindings defaultBindings = defaultContext.getBindings(ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context1 = new SimpleScriptContext(); + context1.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context2 = new SimpleScriptContext(); + context2.getBindings(ScriptContext.ENGINE_SCOPE).put("foo", defaultBindings.get("foo")); + + engine.eval("foo = 44;", context1); + engine.eval("print(foo);", context1); + engine.eval("print(foo);", context2); + } + + private static void test6() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + ScriptContext defaultContext = engine.getContext(); + defaultContext.getBindings(ScriptContext.GLOBAL_SCOPE).put("foo", "hello"); + + ScriptContext customContext = new SimpleScriptContext(); + customContext.setBindings(defaultContext.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.ENGINE_SCOPE); + + Bindings bindings = new SimpleBindings(); + bindings.put("foo", "world"); + customContext.setBindings(bindings, ScriptContext.GLOBAL_SCOPE); + +// engine.eval("foo = 23;"); // overrides foo in all contexts, why??? + + engine.eval("print(foo)"); // hello + engine.eval("print(foo)", customContext); // world + engine.eval("print(foo)", defaultContext); // hello + } + + private static void test5() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + engine.eval("var obj = { foo: 'foo' };"); + engine.eval("function printFoo() { print(obj.foo) };"); + + ScriptContext defaultContext = engine.getContext(); + Bindings defaultBindings = defaultContext.getBindings(ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context1 = new SimpleScriptContext(); + context1.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context2 = new SimpleScriptContext(); + context2.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + engine.eval("obj.foo = 'bar';", context1); + engine.eval("printFoo();", context1); + engine.eval("printFoo();", context2); + } + + private static void test4() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + engine.eval("function foo() { print('bar') };"); + + ScriptContext defaultContext = engine.getContext(); + Bindings defaultBindings = defaultContext.getBindings(ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context = new SimpleScriptContext(); + context.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + engine.eval("foo();", context); + System.out.println(context.getAttribute("foo")); + } + + private static void test3() throws ScriptException { + NashornScriptEngine engine = createEngine(); + + ScriptContext defaultContext = engine.getContext(); + Bindings defaultBindings = defaultContext.getBindings(ScriptContext.ENGINE_SCOPE); + + SimpleScriptContext context = new SimpleScriptContext(); + context.setBindings(defaultBindings, ScriptContext.ENGINE_SCOPE); + + engine.eval("function foo() { print('bar') };", context); + engine.eval("foo();", context); + + Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE); + System.out.println(bindings.get("foo")); + System.out.println(context.getAttribute("foo")); + } + + private static void test2() throws ScriptException { + NashornScriptEngine engine = createEngine(); + engine.eval("function foo() { print('bar') };"); + + SimpleScriptContext context = new SimpleScriptContext(); + engine.eval("print(Function);", context); + engine.eval("foo();", context); + } + + private static void test1() throws ScriptException { + NashornScriptEngine engine = createEngine(); + engine.eval("function foo() { print('bar') };"); + engine.eval("foo();"); + } + + private static NashornScriptEngine createEngine() { + return (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn"); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn2.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn2.java new file mode 100644 index 0000000..b89bda9 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn2.java @@ -0,0 +1,39 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.ScriptObjectMirror; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.io.FileReader; +import java.util.Arrays; + +/** + * Calling java methods from javascript with nashorn. + * + * @author Benjamin Winterberg + */ +public class Nashorn2 { + + public static String fun(String name) { + System.out.format("Hi there from Java, %s", name); + return "greetings from java"; + } + + public static void fun2(Object object) { + System.out.println(object.getClass()); + } + + public static void fun3(ScriptObjectMirror mirror) { + System.out.println(mirror.getClassName() + ": " + Arrays.toString(mirror.getOwnKeys(true))); + } + + public static void fun4(ScriptObjectMirror person) { + System.out.println("Full Name is: " + person.callMember("getFullName")); + } + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval(new FileReader("java8-nashorn/src/main/resources/nashorn2.js")); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn3.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn3.java new file mode 100644 index 0000000..fba357a --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn3.java @@ -0,0 +1,18 @@ +package io.github.biezhi.java8.nashorn; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * Working with java types from javascript. + * + * @author Benjamin Winterberg + */ +public class Nashorn3 { + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn3.js')"); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn4.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn4.java new file mode 100644 index 0000000..1a1642e --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn4.java @@ -0,0 +1,18 @@ +package io.github.biezhi.java8.nashorn; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * Working with java types from javascript. + * + * @author Benjamin Winterberg + */ +public class Nashorn4 { + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("loadWithNewGlobal('java8-nashorn/src/main/resources/nashorn4.js')"); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn5.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn5.java new file mode 100644 index 0000000..47c0d94 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn5.java @@ -0,0 +1,29 @@ +package io.github.biezhi.java8.nashorn; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * Bind java objects to custom javascript objects. + * + * @author Benjamin Winterberg + */ +public class Nashorn5 { + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn5.js')"); + + Invocable invocable = (Invocable) engine; + + Product product = new Product(); + product.setName("Rubber"); + product.setPrice(1.99); + product.setStock(1037); + + Object result = invocable.invokeFunction("getValueOfGoods", product); + System.out.println(result); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn6.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn6.java new file mode 100644 index 0000000..2e1adb7 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn6.java @@ -0,0 +1,36 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.ScriptObjectMirror; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * Using Backbone Models from Nashorn. + * + * @author Benjamin Winterberg + */ +public class Nashorn6 { + + public static void main(String[] args) throws Exception { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn6.js')"); + + Invocable invocable = (Invocable) engine; + + Product product = new Product(); + product.setName("Rubber"); + product.setPrice(1.99); + product.setStock(1337); + + ScriptObjectMirror result = (ScriptObjectMirror) + invocable.invokeFunction("calculate", product); + System.out.println(result.get("name") + ": " + result.get("valueOfGoods")); + } + + public static void getProduct(ScriptObjectMirror result) { + System.out.println(result.get("name") + ": " + result.get("valueOfGoods")); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn7.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn7.java new file mode 100644 index 0000000..8f7b584 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn7.java @@ -0,0 +1,43 @@ +package io.github.biezhi.java8.nashorn; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +/** + * @author Benjamin Winterberg + */ +public class Nashorn7 { + + public static class Person { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getLengthOfName() { + return name.length(); + } + } + + public static void main(String[] args) throws ScriptException, NoSuchMethodException { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("function foo(predicate, obj) { return !!(eval(predicate)); };"); + + Invocable invocable = (Invocable) engine; + + Person person = new Person(); + person.setName("Hans"); + + String predicate = "obj.getLengthOfName() >= 4"; + Object result = invocable.invokeFunction("foo", predicate, person); + System.out.println(result); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn8.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn8.java new file mode 100644 index 0000000..c06893e --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn8.java @@ -0,0 +1,22 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +/** + * @author Benjamin Winterberg + */ +public class Nashorn8 { + public static void main(String[] args) throws ScriptException, NoSuchMethodException { + NashornScriptEngine engine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn8.js')"); + + engine.invokeFunction("evaluate1"); // [object global] + engine.invokeFunction("evaluate2"); // [object Object] + engine.invokeFunction("evaluate3", "Foobar"); // Foobar + engine.invokeFunction("evaluate3", new Person("John", "Doe")); // [object global] <- ??????? + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn9.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn9.java new file mode 100644 index 0000000..9766792 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Nashorn9.java @@ -0,0 +1,31 @@ +package io.github.biezhi.java8.nashorn; + +import jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.concurrent.TimeUnit; + +/** + * @author Benjamin Winterberg + */ +public class Nashorn9 { + + public static void main(String[] args) throws ScriptException, NoSuchMethodException { + NashornScriptEngine engine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn"); + engine.eval("load('java8-nashorn/src/main/resources/nashorn9.js')"); + + long t0 = System.nanoTime(); + + double result = 0; + for (int i = 0; i < 1000; i++) { + double num = (double) engine.invokeFunction("testPerf"); + result += num; + } + + System.out.println(result > 0); + + long took = System.nanoTime() - t0; + System.out.format("Elapsed time: %d ms", TimeUnit.NANOSECONDS.toMillis(took)); + } +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Person.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Person.java new file mode 100644 index 0000000..5715159 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Person.java @@ -0,0 +1,16 @@ +package io.github.biezhi.java8.nashorn; + +/** +* @author Benjamin Winterberg +*/ +public class Person { + public String firstName; + public String lastName; + + public Person() {} + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Product.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Product.java new file mode 100644 index 0000000..e97a6c8 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/Product.java @@ -0,0 +1,12 @@ +package io.github.biezhi.java8.nashorn; + +import lombok.Data; + +@Data +public class Product { + private String name; + private double price; + private int stock; + private double valueOfGoods; + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/SuperRunner.java b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/SuperRunner.java new file mode 100644 index 0000000..00120c5 --- /dev/null +++ b/java8-nashorn/src/main/java/io/github/biezhi/java8/nashorn/SuperRunner.java @@ -0,0 +1,10 @@ +package io.github.biezhi.java8.nashorn; + +public class SuperRunner implements Runnable { + + @Override + public void run() { + System.out.println("super run"); + } + +} \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn1.js b/java8-nashorn/src/main/resources/nashorn1.js new file mode 100644 index 0000000..b342405 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn1.js @@ -0,0 +1,8 @@ +var fun1 = function(name) { + print('Hi there from Javascript, ' + name); + return "greetings from javascript"; +}; + +var fun2 = function (object) { + print("JS Class Definition: " + Object.prototype.toString.call(object)); +}; \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn10.js b/java8-nashorn/src/main/resources/nashorn10.js new file mode 100644 index 0000000..9c572d5 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn10.js @@ -0,0 +1,29 @@ +var results = []; + +var Context = function () { + this.foo = 'bar'; +}; + +Context.prototype.testArgs = function () { + if (arguments[0]) { + results.push(true); + } + if (arguments[1]) { + results.push(true); + } + if (arguments[2]) { + results.push(true); + } + if (arguments[3]) { + results.push(true); + } +}; + +var testPerf = function () { + var context = new Context(); + context.testArgs(); + context.testArgs(1); + context.testArgs(1, 2); + context.testArgs(1, 2, 3); + context.testArgs(1, 2, 3, 4); +}; \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn2.js b/java8-nashorn/src/main/resources/nashorn2.js new file mode 100644 index 0000000..958ba49 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn2.js @@ -0,0 +1,35 @@ +var Nashorn2 = Java.type('io.github.biezhi.java8.nashorn.Nashorn2'); +var result = Nashorn2.fun('John Doe'); +print('\n' + result); + +Nashorn2.fun2(123); +Nashorn2.fun2(49.99); +Nashorn2.fun2(true); +Nashorn2.fun2("hi there") +Nashorn2.fun2(String("bam")) +Nashorn2.fun2(new Number(23)); +Nashorn2.fun2(new Date()); +Nashorn2.fun2(new RegExp()); +Nashorn2.fun2({foo: 'bar'}); + + +print('passing object hash:'); +Nashorn2.fun3({ + foo: 'bar', + bar: 'foo' +}); + + +print('passing custom person object:'); + +function Person(firstName, lastName) { + this.firstName = firstName; + this.lastName = lastName; + this.getFullName = function() { + return this.firstName + " " + this.lastName; + } +} + +var person1 = new Person("Peter", "Parker"); +Nashorn2.fun3(person1); +Nashorn2.fun4(person1); \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn3.js b/java8-nashorn/src/main/resources/nashorn3.js new file mode 100644 index 0000000..c58114e --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn3.js @@ -0,0 +1,121 @@ +print('------------------'); +print('IntArray:'); + +var IntArray = Java.type('int[]'); + +var array = new IntArray(5); +array[0] = 5; +array[1] = 4; +array[2] = 3; +array[3] = 2; +array[4] = 1; + +try { + array[5] = 23; +} catch (e) { + print(e.message); +} + +array[0] = "17"; +print(array[0]); + +array[0] = "wrong type"; +print(array[0]); + +array[0] = "17.3"; +print(array[0]); + +print('------------------'); + +for (var i in array) print(i); + +print('------------------'); + +for each (var val in array) print(val); + +print('------------------'); +print('ArrayList:'); + +var ArrayList = Java.type('java.util.ArrayList'); + +var list = new ArrayList(); +list.add('a'); +list.add('b'); +list.add('c'); + +for each (var el in list) print(el); + + +print('------------------'); +print('HashMap:'); + +var HashMap = Java.type('java.util.HashMap'); + +var map = new HashMap(); +map.put('foo', 'foo1'); +map.put('bar', 'bar1'); + +for each(var e in map.keySet()) print(e); + +for each(var e in map.values()) print(e); + + +print('------------------'); +print('Streams:'); + +var list2 = new ArrayList(); +list2.add("ddd2"); +list2.add("aaa2"); +list2.add("bbb1"); +list2.add("aaa1"); +list2.add("bbb3"); +list2.add("ccc"); +list2.add("bbb2"); +list2.add("ddd1"); + +list2 + .stream() + .filter(function(el) { + return el.startsWith("aaa"); + }) + .sorted() + .forEach(function(el) { + print(el); + }); + + + +print('------------------'); +print('Extend:'); + +var Runnable = Java.type('java.lang.Runnable'); +var Printer = Java.extend(Runnable, { + run: function() { + print('This was printed from a seperate thread.'); + } +}); + +var Thread = Java.type('java.lang.Thread'); +new Thread(new Printer()).start(); + +new Thread(function() { + print('this was printed from another thread'); +}).start(); + + +print('------------------'); +print('Parameter Overload:'); + +var System = Java.type('java.lang.System'); + +System.out.println(10); +System.out["println"](11.0); +System.out["println(double)"](12); + +print('------------------'); +print('JavaBeans:'); + +var Date = Java.type('java.util.Date'); +var date = new Date(); +date.year += 1900; +System.out.println(date.year); \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn4.js b/java8-nashorn/src/main/resources/nashorn4.js new file mode 100644 index 0000000..43dc139 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn4.js @@ -0,0 +1,98 @@ +// function literal with no braces + +function sqr(x) x * x; + +print(sqr(3)); + + +// for each + +var array = [1, 2, 3, 4]; +for each (var num in array) print(num); + + +// object literals in constructors + +var runnable = new java.lang.Runnable() { + run: function() { + print('on the run'); + } +}; + +runnable.run(); + + +// bind properties + +var o1 = {}; +var o2 = { foo: 'bar'}; + +Object.bindProperties(o1, o2); + +print(o1.foo); +o1.foo = 'BAM'; +print(o2.foo); + + +// string trim + +print(" hehe".trimLeft()); +print("hehe ".trimRight() + "he"); + + +// whereis +print(__FILE__, __LINE__, __DIR__); + + +// java import + +var imports = new JavaImporter(java.io, java.lang); +with (imports) { + var file = new File(__FILE__); + System.out.println(file.getAbsolutePath()); + // /path/to/my/script.js +} + + +// convert iterable to js array + +var list = new java.util.ArrayList(); +list.add("s1"); +list.add("s2"); +list.add("s3"); + +var jsArray = Java.from(list); +print(jsArray); +print(Object.prototype.toString.call(jsArray)); + + +// convert js array to java array + +var javaArray = Java.to([3, 5, 7, 11], "int[]"); +print(Object.prototype.toString.call(javaArray)); + + +// calling super + +var SuperRunner = Java.type('io.github.biezhi.java8.nashorn.SuperRunner'); +var Runner = Java.extend(SuperRunner); + +var runner = new Runner() { + run: function() { + Java.super(runner).run(); + print('on my run'); + } +} +runner.run(); + + + +// load + +load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'); + +var odds = _.filter([1, 2, 3, 4, 5, 6], function (num) { + return num % 2 == 1; +}); + +print(odds); \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn5.js b/java8-nashorn/src/main/resources/nashorn5.js new file mode 100644 index 0000000..f7d0176 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn5.js @@ -0,0 +1,22 @@ +function Product(name) { + this.name = name; +} + +Product.prototype.stock = 0; +Product.prototype.price = 0; +Product.prototype.getValueOfGoods = function() { + return this.stock * this.price; +}; + +var product = new Product('Pencil'); +product.price = 4.99; +product.stock = 78; + +print('Value of Goods: ' + product.getValueOfGoods()); + + +var getValueOfGoods = function(javaProduct) { + var jsProduct = new Product(); + Object.bindProperties(jsProduct, javaProduct); + return jsProduct.getValueOfGoods(); +}; \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn6.js b/java8-nashorn/src/main/resources/nashorn6.js new file mode 100644 index 0000000..bfc8053 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn6.js @@ -0,0 +1,47 @@ +load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'); +load('http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js'); + + +// simple backbone model: +// valueOfGoods will automatically be calculated when stock or price changes +var Product = Backbone.Model.extend({ + defaults: { + stock: 0, + price: 0.0, + name:'', + valueOfGoods: 0.0 + }, + + initialize: function() { + this.on('change:stock change:price', function() { + var stock = this.get('stock'); + var price = this.get('price'); + var valueOfGoods = this.getValueOfGoods(stock, price); + this.set('valueOfGoods', valueOfGoods); + }); + }, + + getValueOfGoods: function(stock, price) { + return stock * price; + } +}); + +var product = new Product(); +product.set('name', 'Pencil'); +product.set('stock', 1000); +product.set('price', 3.99); + + +// pass backbone model to java method +var Nashorn6 = Java.type('io.github.biezhi.java8.nashorn.Nashorn6'); +Nashorn6.getProduct(product.attributes); + + +// bind java object to backbone model and pass result back to java +var calculate = function(javaProduct) { + var model = new Product(); + model.set('name', javaProduct.name); + model.set('price', javaProduct.price); + model.set('stock', javaProduct.stock); + return model.attributes; +}; \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn7.js b/java8-nashorn/src/main/resources/nashorn7.js new file mode 100644 index 0000000..9246f16 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn7.js @@ -0,0 +1,27 @@ +function sqrt(x) x * x +print(sqrt(3)); + +var array = [1, 2, 3, 4]; +for each (var num in array) print(num); + +var runnable = new java.lang.Runnable() { + run: function () { + print('on the run'); + } +}; + +runnable.run(); + +var System = Java.type('java.lang.System'); +System.out["println(double)"](12); + +var Arrays = Java.type("java.util.Arrays"); +var javaArray = Java.to([2, 3, 7, 11, 14], "int[]"); + +Arrays.stream(javaArray) + .filter(function (num) { + return num % 2 === 1; + }) + .forEach(function (num) { + print(num); + }); \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn8.js b/java8-nashorn/src/main/resources/nashorn8.js new file mode 100644 index 0000000..d7bb6a6 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn8.js @@ -0,0 +1,18 @@ +var evaluate1 = function () { + (function () { + print(eval("this")); + }).call(this); +}; + +var evaluate2 = function () { + var context = {}; + (function () { + print(eval("this")); + }).call(context); +}; + +var evaluate3 = function (context) { + (function () { + print(eval("this")); + }).call(context); +}; \ No newline at end of file diff --git a/java8-nashorn/src/main/resources/nashorn9.js b/java8-nashorn/src/main/resources/nashorn9.js new file mode 100644 index 0000000..e60e2b0 --- /dev/null +++ b/java8-nashorn/src/main/resources/nashorn9.js @@ -0,0 +1,9 @@ +var size = 100000; + +var testPerf = function () { + var result = Math.floor(Math.random() * size) + 1; + for (var i = 0; i < size; i++) { + result += i; + } + return result; +}; \ No newline at end of file diff --git a/java8-optional/README.md b/java8-optional/README.md index d823b09..1338529 100644 --- a/java8-optional/README.md +++ b/java8-optional/README.md @@ -5,7 +5,7 @@ | 方法 | 描述 | |:-----:|:-------| | `empty` | 返回一个空的 Optional 实例 | -| `filter` | 如果值存在并且满足提供的谓词, 就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象 | +| `filter` | 如果值存在并且满足提供的断言, 就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象 | | `map` | 如果值存在,就对该值执行提供的 mapping 函数调用 | | `flatMap` | 如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返 回一个空的 Optional 对象 | | `get` | 如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常 | diff --git a/pom.xml b/pom.xml index dce138b..5c15e63 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ java8-proper java8-concurrent java8-growing + java8-completablefuture