-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathCallable_Future_Java.txt
More file actions
191 lines (144 loc) · 6.83 KB
/
Callable_Future_Java.txt
File metadata and controls
191 lines (144 loc) · 6.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
Java Concurrency: Executing Value-Returning Tasks with Callable and Future
This Java Concurrency tutorial guides you how to execute a task that computes a value and wait for the result available. This can be done by submitting a Callable task to an ExecutorService and getting the result via a Future object.
The ExecutorServiceinterface defines a method that allows us to execute such kind of value-returning tasks:
<T> Future<T> submit(Callable<T> task)
Here, the type parameter Tis the return type of the task. You submit a task that implements the Callable interface which defines only one method as follows:
public interface Callable<T> {
public T call();
}
The purpose of the Callable interface is similar to Runnable, but its method returns a value of type T.
Once the task is submitted, the executor immediately returns an object of type Future representing the pending results of the task, for example:
Callable<Integer> task = new task that returns an Integer value;
Future<Integer> result = executor.submit(task);
Then you can invoke the Future’s get() method to obtain the result upon successful completion. There are two overloads of this method defined as follows:
public interface Future<T> {
T get();
T get(long timeout, TimeUnit unit);
}
The first overload version waits if necessary for the computation to complete and then retrieves its result:
1
Integer value = result.get();
This method blocks the current thread to wait until the computation completes and returns the value.
In case you want to wait only for a specified amount of time, use the second overload version:
1
Integer value = result.get(2, TimeUnit.SECONDS);
This call wais if necessary for at most 2 seconds for the computation to complete, and then retrieves the result if available. If the task takes longer time to complete, the call returns null. It throws TimeoutException if the wait timed out.
And both methods throw ExecutionException if the task threw an exception, and throw InterruptedException if the current thread was interrupted while waiting.
Now, let’s see a complete example.
Suppose that we have two tasks: the first calculates the factorial value of N numbers, and the second computes the sum of N numbers.
Implementing the Callable interface, the first task is written as follows:
import java.util.concurrent.*;
/**
* FactorialCalculator.java
* This class represents a task that computes and returns factorial value
* of N numbers.
* @author
*/
public class FactorialCalculator implements Callable<Integer> {
private int n;
public FactorialCalculator(int n) {
this.n = n;
}
public Integer call() {
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return result;
}
}
Here we use the sleep() method to fake the computation time.
And code for the second task:
import java.util.concurrent.*;
/**
* SumCalculator.java
* This class represents a task that computes and returns value of
* sum of N numbers.
* @author
*/
public class SumCalculator implements Callable<Integer> {
private int n;
public SumCalculator(int n) {
this.n = n;
}
public Integer call() {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return sum;
}
}
And the following program submits two tasks above to a fixed thread pool executor:
import java.util.concurrent.*;
/**
* CallableAndFutureExample.java
* This program demonstrates how to execute value-returning tasks
* and wait for the results available.
*
*/
public class CallableAndFutureExample {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> sumResult = pool.submit(new SumCalculator(100000));
Future<Integer> factorialResult = pool.submit(new FactorialCalculator(8));
try {
Integer sumValue = sumResult.get();
System.out.println("Sum Value = " + sumValue);
Integer factorialValue = factorialResult.get();
System.out.println("Factorial Value = " + factorialValue);
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
pool.shutdown();
}
}
Run this program and observe the result. The first task, SumCalculator takes 2 seconds to complete and you see the result displayed after 2 seconds:
1
Sum Value = 705082704
The second task, FactorialCalculator takes 5 seconds to complete, so you see the result 3 seconds after the first result:
1
Factorial Value = 40320
Cancelling a Task:
The Future interface defines the following method that allows you to cancel a task:
boolean cancel(boolean mayInterruptIfRunning)
This method returns false if the task has already completed, has already been cancelled, or could not be cancelled for some other reason.
If this method returns true:
- The task will never run if it has not started.
- In case the task has already started, you can decide to interrupt the thread executing the task by specifying the flag mayInterruptIfRunning = true. Otherwise, the task continues until completes.
For example, the following code will cancel the task if it has been running longer than 3 seconds:
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> factorialResult = pool.submit(new FactorialCalculator(8));
try {
Integer factorialValue = null;
try {
factorialValue = factorialResult.get(3, TimeUnit.SECONDS);
} catch (TimeoutException ex ) {
ex.printStackTrace();
}
if (factorialValue != null) {
System.out.println("Factorial Value = " + factorialValue);
} else {
boolean cancelled = factorialResult.cancel(true);
System.out.println("Task cancelled? " + cancelled);
}
} catch (InterruptedException | ExecutionException ex ) {
ex.printStackTrace();
}
pool.shutdown();
Run this code and you will see that after 3 seconds, it throws a TimeoutException because the wait timed out, and throws an InterruptedException because the thread executing the task was interrupted because of the call:
1
boolean cancelled = factorialResult.cancel(true);
In addition, the Future interface provides methods for checking the completion status:
boolean isDone(): returns true if this task completed.
boolean isCancelled(): returns true if this task was cancelled before it completed normally.