├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
└── com
└── packt
└── tfesenko
└── multithreading
├── section1
├── AppleTree.java
├── Lesson2.java
├── Lesson3.java
├── Lesson4.java
└── Lesson5.java
├── section2
├── Lesson1.java
├── Lesson2.java
├── Lesson3.java
├── Lesson4.java
└── Lesson5.java
├── section3
├── Lesson2.java
├── Lesson3.java
└── Lesson4.java
├── section4
├── Lesson1.java
├── Lesson2.java
├── Lesson3.java
└── Lesson4.java
└── section5
├── Lesson1.java
├── Lesson2.java
├── Lesson3.java
└── Lesson4.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Java Concurrency and Multithreading in Practice
5 | This is the code repository for [Java Concurrency and Multithreading in Practice]( https://www.packtpub.com/application-development/java-concurrency-and-multithreading-practice-video), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish.
6 | ## About the Video Course
7 | Multi-core processors are everywhere—from super-computers to mobile devices right in your pocket. That's why a modern developer must know how to leverage the power of multithreading.
8 | This course will teach you how to use parallelism and concurrency in Java. You will learn how to parallelize tasks and functions with the ForkJoin framework and Streams. You will also learn how to work with the very popular Reactive Streams recently introduced to Java. Furthermore, you will master concurrent collections and lower-level synchronization techniques with locks.
9 |
10 | This course conveniently provides quizzes to evaluate your knowledge and help you retain the new concepts.
11 |
12 | By the end of this practical training course, you will have the knowledge to write elegant programs for multicore computers with enhanced performance and improved responsiveness.
13 |
14 |
What You Will Learn
15 |
16 |
17 |
Build efficient and elegant code with popular parallel Java frameworks, including ForkJoin and Streams functions
18 |
Master Reactive Streams to process data
19 |
Explore the existing thread-safe collections and types, to avoid reinventing the wheel
20 |
Understand how threads work in Java and how to manage them
21 |
Leverage multithreading to increase your application's performance
22 |
23 | ## Instructions and Navigation
24 | ### Assumed Knowledge
25 | If you are a Java developer keen to learn how to write modern parallel and concurrent programs to improve application performance, this course is for you. Some basic workable knowledge of Java is assumed.
26 | ### Technical Requirements
27 |
28 | Minimum Hardware Requirements
29 |
For successful completion of this course, students will require the computer systems with at least the following:
30 |
OS: Windows 7 and above
31 |
Processor: 1.4 GHz 32-bit (x86)
32 |
Memory: 4GB
33 |
Storage: 2GB
34 |
35 |
36 | Recommended Hardware Requirements
37 |
For an optimal experience with hands-on labs and other practical activities, we recommend the following configuration:
38 |
OS: Windows 10
39 |
Processor: Dual Core 1.8Ghz (64-bit) or better configuration
40 |
Memory: 4GB or more
41 |
Storage: 2GB or more
42 |
43 |
44 | Software Requirements
45 |
Operating system: Windows, Mac, or Linux
46 |
Java IDE of your choice, e.g. Eclipse or IntelliJ IDEA
47 |
Java 8+ installed
48 |
49 |
50 |
51 | ## Related Products
52 | * [Mastering Odoo 12 Development [Video]](https://www.packtpub.com/business/mastering-odoo-12-development-video?utm_source=github&utm_medium=repository&utm_campaign=9781789139280)
53 |
54 | * [High-Performance Computing with Python 3.x [Video]](https://www.packtpub.com/application-development/high-performance-computing-python-3x-video?utm_source=github&utm_medium=repository&utm_campaign=9781789956252)
55 |
56 | * [Functional Programming in 7 Days [Video]](https://www.packtpub.com/application-development/functional-programming-7-days-video?utm_source=github&utm_medium=repository&utm_campaign=9781788990295)
57 |
58 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 | com.packt.tfesenko
6 | concurrency
7 | 0.0.1-SNAPSHOT
8 | Java Concurrency and Multithreading in Practice
9 | Java Concurrency and Multithreading in Practice
10 |
11 | 1.9
12 | 1.9
13 |
14 |
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section1/AppleTree.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section1;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | public class AppleTree {
8 |
9 | public static AppleTree[] newTreeGarden(int size) {
10 | AppleTree[] appleTrees = new AppleTree[size];
11 | for (int i = 0; i < appleTrees.length; i++) {
12 | appleTrees[i] = new AppleTree("🌳#" + i);
13 | }
14 | return appleTrees;
15 | }
16 |
17 | private final String treeLabel;
18 | private final int numberOfApples;
19 |
20 | public AppleTree(String treeLabel) {
21 | this.treeLabel = treeLabel;
22 | numberOfApples = 3;
23 | }
24 |
25 | public int pickApples(String workerName) {
26 | try {
27 | //System.out.printf("%s started picking apples from %s \n", workerName, treeLabel);
28 | TimeUnit.SECONDS.sleep(1);
29 | System.out.printf("%s picked %d 🍏s from %s \n", workerName, numberOfApples, treeLabel);
30 | } catch (InterruptedException e) {
31 | e.printStackTrace();
32 | }
33 | return numberOfApples;
34 | }
35 |
36 | public int pickApples() {
37 | return pickApples(toLabel(Thread.currentThread().getName()));
38 | }
39 |
40 | private String toLabel(String threadName) {
41 | HashMap threadNameToLabel = new HashMap<>();
42 | threadNameToLabel.put("ForkJoinPool.commonPool-worker-1", "Alice");
43 | threadNameToLabel.put("ForkJoinPool.commonPool-worker-2", "Bob");
44 | threadNameToLabel.put("ForkJoinPool.commonPool-worker-3", "Carol");
45 | threadNameToLabel.put("ForkJoinPool.commonPool-worker-4", "Dan");
46 |
47 | return threadNameToLabel.getOrDefault(threadName, threadName);
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section1/Lesson2.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section1;
2 |
3 | import static java.util.Arrays.asList;
4 |
5 | import java.util.concurrent.Callable;
6 | import java.util.concurrent.ForkJoinPool;
7 |
8 | public class Lesson2 {
9 | public static void main(String[] args) {
10 | AppleTree[] appleTrees = AppleTree.newTreeGarden(6);
11 |
12 | Callable applePicker1 = createApplePicker(appleTrees, 0, 2, "Alex");
13 | Callable applePicker2 = createApplePicker(appleTrees, 2, 4, "Bob");
14 | Callable applePicker3 = createApplePicker(appleTrees, 4, 6, "Carol");
15 |
16 | ForkJoinPool.commonPool().invokeAll(asList(applePicker1, applePicker2, applePicker3));
17 |
18 | System.out.println();
19 | System.out.println("All fruits collected!");
20 | }
21 |
22 | public static Callable createApplePicker(AppleTree[] appleTrees, int fromIndexInclusive, int toIndexExclusive,
23 | String workerName) {
24 | return () -> {
25 | for (int i = fromIndexInclusive; i < toIndexExclusive; i++) {
26 | appleTrees[i].pickApples(workerName);
27 | }
28 | return null;
29 | };
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section1/Lesson3.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section1;
2 |
3 | import java.util.concurrent.ForkJoinPool;
4 | import java.util.concurrent.RecursiveTask;
5 | import java.util.stream.IntStream;
6 |
7 | public class Lesson3 {
8 |
9 | public static void main(String[] args) {
10 | AppleTree[] appleTrees = AppleTree.newTreeGarden(12);
11 | ForkJoinPool pool = ForkJoinPool.commonPool();
12 |
13 | PickFruitTask task = new PickFruitTask(appleTrees, 0, appleTrees.length - 1);
14 | int result = pool.invoke(task);
15 |
16 | System.out.println();
17 | System.out.println("Total apples picked: " + result);
18 | }
19 |
20 | public static class PickFruitTask extends RecursiveTask {
21 |
22 | private final AppleTree[] appleTrees;
23 | private final int startInclusive;
24 | private final int endInclusive;
25 |
26 | private final int taskThreadshold = 4;
27 |
28 | public PickFruitTask(AppleTree[] array, int startInclusive, int endInclusive) {
29 | this.appleTrees = array;
30 | this.startInclusive = startInclusive;
31 | this.endInclusive = endInclusive;
32 | }
33 |
34 | @Override
35 | protected Integer compute() {
36 | if (endInclusive - startInclusive < taskThreadshold) {
37 | return doCompute();
38 | }
39 | int midpoint = startInclusive + (endInclusive - startInclusive) / 2;
40 |
41 | PickFruitTask leftSum = new PickFruitTask(appleTrees, startInclusive, midpoint);
42 | PickFruitTask rightSum = new PickFruitTask(appleTrees, midpoint + 1, endInclusive);
43 |
44 | rightSum.fork(); // computed asynchronously
45 |
46 | return leftSum.compute()// computed synchronously: immediately and in the current thread
47 | + rightSum.join();
48 | }
49 |
50 | protected Integer doCompute() {
51 | return IntStream.rangeClosed(startInclusive, endInclusive)//
52 | .map(i -> appleTrees[i].pickApples())//
53 | .sum();
54 |
55 | // Equivalent with a "for" loop :)
56 | // int result = 0;
57 | // for (int i = startInclusive; i <= endInclusive; i++) {
58 | // result += array[i].pickApples();
59 | // }
60 | // return result;
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section1/Lesson4.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section1;
2 |
3 | import java.util.concurrent.ForkJoinPool;
4 | import java.util.concurrent.RecursiveAction;
5 | import java.util.concurrent.TimeUnit;
6 | import java.util.stream.IntStream;
7 |
8 | public class Lesson4 {
9 |
10 | public static void main(String[] args) throws InterruptedException {
11 | AppleTree[] appleTrees = AppleTree.newTreeGarden(12);
12 | PickFruitAction task = new PickFruitAction(appleTrees, 0, appleTrees.length - 1);
13 |
14 | ForkJoinPool pool = ForkJoinPool.commonPool();
15 |
16 | pool.invoke(task);
17 | // try this: pool.execute(task);
18 | // try this: pool.execute(task); task.join();
19 | // try this: pool.execute(task); pool.awaitTermination(10, TimeUnit.SECONDS);
20 |
21 | System.out.println();
22 | System.out.println("Done!");
23 | }
24 |
25 | public static class PickFruitAction extends RecursiveAction {
26 |
27 | private final AppleTree[] appleTrees;
28 | private final int startInclusive;
29 | private final int endInclusive;
30 |
31 | private final int taskThreadshold = 4;
32 |
33 | public PickFruitAction(AppleTree[] array, int startInclusive, int endInclusive) {
34 | this.appleTrees = array;
35 | this.startInclusive = startInclusive;
36 | this.endInclusive = endInclusive;
37 | }
38 |
39 | @Override
40 | protected void compute() {
41 | if (endInclusive - startInclusive < taskThreadshold) {
42 | doCompute();
43 | return;
44 | }
45 | int midpoint = startInclusive + (endInclusive - startInclusive) / 2;
46 |
47 | PickFruitAction leftSum = new PickFruitAction(appleTrees, startInclusive, midpoint);
48 | PickFruitAction rightSum = new PickFruitAction(appleTrees, midpoint + 1, endInclusive);
49 |
50 | rightSum.fork(); // computed asynchronously
51 | leftSum.compute();// computed synchronously: immediately and in the current thread
52 | rightSum.join();
53 | }
54 |
55 | protected void doCompute() {
56 | IntStream.rangeClosed(startInclusive, endInclusive)//
57 | .forEach(i -> appleTrees[i].pickApples());
58 |
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section1/Lesson5.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section1;
2 |
3 | import java.util.concurrent.ForkJoinPool;
4 | import java.util.concurrent.RecursiveTask;
5 | import java.util.concurrent.TimeUnit;
6 | import java.util.stream.IntStream;
7 |
8 | public class Lesson5 {
9 |
10 | private static final int treeNumber = 12;
11 |
12 | public static void main(String[] args) {
13 | AppleTree[] appleTrees = AppleTree.newTreeGarden(treeNumber);
14 | ForkJoinPool pool = ForkJoinPool.commonPool();
15 |
16 | PickFruitTask task = new PickFruitTask(appleTrees, 0, appleTrees.length - 1);
17 | int result = pool.invoke(task);
18 |
19 | System.out.println();
20 | System.out.println("Total apples picked: " + result);
21 | }
22 |
23 | public static class SomethingWentWrongException extends Exception {
24 | }
25 |
26 | public static class PickFruitTask extends RecursiveTask {
27 |
28 | private final AppleTree[] appleTrees;
29 | private final int startInclusive;
30 | private final int endInclusive;
31 |
32 | private final int taskThreadshold = 4;
33 |
34 | public PickFruitTask(AppleTree[] array, int startInclusive, int endInclusive) {
35 | this.appleTrees = array;
36 | this.startInclusive = startInclusive;
37 | this.endInclusive = endInclusive;
38 | }
39 |
40 | @Override
41 | protected Integer compute() {
42 | // throw an exception for any task from the right side of the array
43 | if (startInclusive >= treeNumber / 2) {
44 | // try this: int throwException = 10/0;
45 | // try this: throw new SomethingWentWrongException();
46 | // try this: completeExceptionally(new SomethingWentWrongException());
47 | }
48 | if (endInclusive - startInclusive < taskThreadshold) {
49 | return doCompute();
50 | }
51 | int midpoint = startInclusive + (endInclusive - startInclusive) / 2;
52 |
53 | PickFruitTask leftSum = new PickFruitTask(appleTrees, startInclusive, midpoint);
54 | PickFruitTask rightSum = new PickFruitTask(appleTrees, midpoint + 1, endInclusive);
55 |
56 | rightSum.fork(); // computed asynchronously
57 |
58 | try {
59 | TimeUnit.MILLISECONDS.sleep(100);
60 | } catch (InterruptedException e) {
61 | // TODO Auto-generated catch block
62 | e.printStackTrace();
63 | }
64 |
65 | // try this: rightSum.cancel(true);
66 |
67 | return leftSum.compute()// computed synchronously: immediately and in the current thread
68 | + rightSum.join();
69 | }
70 |
71 | protected Integer doCompute() {
72 | return IntStream.rangeClosed(startInclusive, endInclusive)//
73 | .map(i -> appleTrees[i].pickApples())//
74 | .sum();
75 |
76 | }
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section2/Lesson1.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section2;
2 |
3 | import java.util.concurrent.ExecutionException;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Executors;
6 | import java.util.concurrent.Future;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | public class Lesson1 {
10 |
11 | public static void main(String[] args) throws InterruptedException, ExecutionException {
12 | demoFutureWithCallable();
13 | demoCallableVsRunnable();
14 | }
15 |
16 | public static void demoFutureWithCallable() throws InterruptedException, ExecutionException {
17 | System.out.println();
18 | System.out.println("Demo Future with Callable");
19 | ExecutorService pool = Executors.newCachedThreadPool();
20 |
21 | Future pizzaPickupOrder = pool.submit(() -> {
22 | System.out.println(" Restaurant> Slicing tomatoes");
23 | System.out.println(" Restaurant> Chopping onions");
24 | System.out.println(" Restaurant> Spreading with tomato sauce and sprinkle with toppings");
25 | System.out.println(" Restaurant> Baking pizza");
26 | TimeUnit.MILLISECONDS.sleep(300);
27 | return new Pizza();
28 | });
29 |
30 | System.out.println("Me: Call my brother");
31 | TimeUnit.MILLISECONDS.sleep(200);
32 | System.out.println("Me: Walk the dog");
33 |
34 | // Try this: pizzaPickupOrder.cancel(true);
35 | if (pizzaPickupOrder.isCancelled()) {
36 | System.out.println("Me: pizza is cancelled, order something else");
37 | System.out.println("pizzaPickupOrder.isDone(): " + pizzaPickupOrder.isDone());
38 | } else if (!pizzaPickupOrder.isDone()) {
39 | System.out.println("Me: Watch a TV show");
40 | }
41 | Pizza pizza = pizzaPickupOrder.get();
42 |
43 | System.out.println("Me: Eat the pizza: " + pizza);
44 |
45 | pool.shutdown();
46 | System.out.println();
47 | System.out.println();
48 | }
49 |
50 | public static void demoCallableVsRunnable() throws InterruptedException, ExecutionException {
51 | System.out.println();
52 | System.out.println("Demo: Callable vs Runnable");
53 | ExecutorService pool = Executors.newCachedThreadPool();
54 |
55 | Runnable makePizza = () -> {
56 | System.out.println(" Restaurant> Slicing tomatoes");
57 | System.out.println(" Restaurant> Chopping onions");
58 | System.out.println(" Restaurant> Spreading with tomato sauce and sprinkle with toppings");
59 | System.out.println(" Restaurant> Baking pizza");
60 | // Compare to Callable: need to handle exception here
61 | try {
62 | TimeUnit.MILLISECONDS.sleep(300);
63 | } catch (InterruptedException e) {
64 | e.printStackTrace();
65 | }
66 | // Compare to Callable: nothing to return
67 | };
68 |
69 | // compare to submit(Callable): Future> here vs Future there
70 | Future> pizzaPickupOrder = pool.submit(makePizza);
71 |
72 | // try this: pool.execute(makePizza);
73 |
74 | System.out.println("Me: Calling my brother");
75 | TimeUnit.MILLISECONDS.sleep(200);
76 | System.out.println("Me: Walk the dog");
77 |
78 | Object pizza = pizzaPickupOrder.get(); // null
79 | System.out.println("Me: Eat the pizza: " + pizza);
80 |
81 | pool.shutdown();
82 | }
83 |
84 | public static class Pizza {
85 |
86 | @Override
87 | public String toString() {
88 | return "Classic margherita";
89 | }
90 |
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section2/Lesson2.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section2;
2 |
3 | import java.util.Random;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.concurrent.ExecutorService;
6 | import java.util.concurrent.Executors;
7 | import java.util.concurrent.Future;
8 | import java.util.concurrent.ScheduledExecutorService;
9 | import java.util.concurrent.ScheduledFuture;
10 | import java.util.concurrent.ThreadFactory;
11 | import java.util.concurrent.TimeUnit;
12 | import java.util.concurrent.atomic.AtomicInteger;
13 |
14 | public class Lesson2 {
15 |
16 | private static final Runnable helloTask = //
17 | () -> System.out.printf("Hello from '%s'\n", Thread.currentThread().getName());
18 |
19 | public static void main(String[] args) throws InterruptedException, ExecutionException {
20 | // a program already has a thread - the main thread
21 | System.out.println("Current thread: " + Thread.currentThread().getName());
22 |
23 | demoThread();
24 | demoThreadsCreatedByThreadPool();
25 | demoDifferentExecutorServices();
26 | demoScheduledExecutorService();
27 | demoThreadFactory();
28 | }
29 |
30 | public static void demoThread() {
31 | System.out.println("Demo Thread");
32 | System.out.println(
33 | "⚠️For demo purpoeses only, don't create/start Threads yourself - use ExecutorService instead!!");
34 |
35 | // submit 10 similar tasks
36 | for (int i = 0; i < 10; i++) {
37 | new Thread(helloTask).start();
38 | }
39 | // The tasks are executed from _ten_ _different_ threads
40 | // 10 > 4 (4 is number of cores of my computer)
41 | // threads are NOT re-used
42 |
43 | System.out.println();
44 | }
45 |
46 | public static void demoThreadsCreatedByThreadPool() throws InterruptedException, ExecutionException {
47 | System.out.println("Demo ThreadPool");
48 | System.out.println("😄Use an ExecutorService to manage threads");
49 |
50 | ExecutorService pool = Executors.newCachedThreadPool();
51 | // submit 10 similar tasks and watch that they are executed from different
52 | // threads
53 | for (int i = 0; i < 10; i++) {
54 | pool.submit(helloTask);
55 | }
56 |
57 | // Unlike thread.start(), threadPool.submit() returns a Future
58 | Future randomNumber = pool.submit(() -> new Random().nextInt());
59 | System.out.println("Random number: " + randomNumber.get());
60 |
61 | pool.shutdown();
62 | System.out.println();
63 | }
64 |
65 | public static void demoThreadFactory() {
66 | System.out.println("Demo ThreadFactory");
67 | System.out.println("😄Use an ExecutorService to manage threads");
68 |
69 | ThreadFactory threadFactory = new ThreadFactory() {
70 | private final AtomicInteger threadNumber = new AtomicInteger(1);
71 |
72 | public Thread newThread(Runnable r) {
73 | Thread thread = new Thread(r);
74 | thread.setName("Hello Thread " + threadNumber.getAndIncrement());
75 | thread.setPriority(Thread.MAX_PRIORITY);
76 | return thread;
77 | }
78 | };
79 |
80 | ExecutorService pool = Executors.newCachedThreadPool(threadFactory);
81 |
82 | // submit 10 similar tasks and watch that they are executed from different
83 | // threads
84 | for (int i = 0; i < 10; i++) {
85 | pool.submit(helloTask);
86 | }
87 |
88 | pool.shutdown();
89 | System.out.println();
90 | }
91 |
92 | public static void demoDifferentExecutorServices() {
93 | System.out.println("Demo different thread pools");
94 |
95 | ExecutorService pool = Executors.newCachedThreadPool();
96 | // Try using these thread pools an how it influences the threads where the tasks
97 | // are executed
98 | // ExecutorService pool = Executors.newFixedThreadPool(5);
99 | // ExecutorService pool = Executors.newFixedThreadPool(1);
100 | // ExecutorService pool = Executors.newSingleThreadExecutor();
101 |
102 | // submit 10 similar tasks and watch that they are executed from different
103 | // threads
104 | for (int i = 0; i < 10; i++) {
105 | // Unlike thread.start(), threadPool.submit() returns a Future
106 | Future> result = pool.submit(helloTask);
107 | }
108 |
109 | // make sure to shut down the pool when finished using it!
110 | pool.shutdown();
111 | System.out.println();
112 | }
113 |
114 | public static void demoScheduledExecutorService() {
115 | System.out.println("Demo scheduled tasks");
116 |
117 | ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
118 |
119 | ScheduledFuture> waterReminder = scheduler.scheduleAtFixedRate(
120 | () -> System.out.println("Hi there, it's time to drink a glass of water"), //
121 | 0, 1, TimeUnit.SECONDS);
122 |
123 | ScheduledFuture> exerciseReminder = scheduler.scheduleAtFixedRate(
124 | () -> System.out.println("Hi there, it's time to exercise"), //
125 | 0, 12, TimeUnit.SECONDS);
126 |
127 | // to cancel the tasks after certain amount of time
128 | Runnable canceller = () -> {
129 | exerciseReminder.cancel(false);
130 | waterReminder.cancel(false);
131 | };
132 | scheduler.schedule(canceller, 15, TimeUnit.SECONDS);
133 | }
134 | }
--------------------------------------------------------------------------------
/src/main/java/com/packt/tfesenko/multithreading/section2/Lesson3.java:
--------------------------------------------------------------------------------
1 | package com.packt.tfesenko.multithreading.section2;
2 |
3 | import java.util.concurrent.CompletableFuture;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.concurrent.ExecutorService;
6 | import java.util.concurrent.Executors;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | public class Lesson3 {
10 |
11 | public static void main(String[] args) throws InterruptedException, ExecutionException {
12 | // executor is not provided, CompletableFuture.supplyAsync will use ForkJoinPool by default
13 | ExecutorService executor = Executors.newCachedThreadPool();
14 |
15 |
16 | final String tomatoes = "Tomatoes";
17 | CompletableFuture sliceTomatoes = CompletableFuture.supplyAsync(() -> {
18 | // try {
19 | // TimeUnit.MILLISECONDS.sleep(10);
20 | // } catch (InterruptedException e) {
21 | // e.printStackTrace();
22 | // }
23 | System.out.println(" Restaurant> Slicing tomatoes");
24 | if (tomatoes == null) {
25 | throw new RuntimeException("No tomatoes");
26 | }
27 | return "Tomatoes ";
28 | }, executor).handle((result, e) -> {
29 | if (result == null) {
30 | System.out.println("Problems with tomatoes");
31 | return "";
32 | }
33 | return result;
34 | });
35 |
36 | CompletableFuture chopOnions = CompletableFuture.supplyAsync(() -> {
37 | System.out.println(" Restaurant> Chopping onions");
38 | return "Onions ";
39 | }, executor);
40 |
41 | CompletableFuture prepIngredients = sliceTomatoes.thenCombine(chopOnions, //
42 | String::concat);
43 |
44 | CompletableFuture