-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScheduledExecutorDemo.java
More file actions
136 lines (123 loc) · 5.3 KB
/
Copy pathScheduledExecutorDemo.java
File metadata and controls
136 lines (123 loc) · 5.3 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
package Phase7_Concurrency.Multithreading;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* ScheduledExecutorService
* ------------------------
* Delayed and recurring tasks without writing your own scheduler.
* <p>
*
* ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
* <p>
*
* The methods
* -----------
* schedule(Runnable, delay, unit) - run once after delay
* schedule(Callable<V>, delay, unit) - run once and produce V
* scheduleAtFixedRate(r, initial, period, unit)
* - START every `period`, regardless
* of how long previous ran
* (catches up after a slow run).
* scheduleWithFixedDelay(r, initial, delay, unit)
* - WAIT `delay` AFTER each run finishes
* (no catch-up).
* <p>
*
* Difference at a glance
* <p>
*
* atFixedRate( period=100 ms ):
* start 0 100 200 300 ... even if a run took 150ms,
* the next still starts at 200.
* <p>
*
* withFixedDelay( delay=100 ms ):
* run, wait 100, run, wait 100, ...
* <p>
*
* Cancelling
* ----------
* ScheduledFuture<?> f = ses.scheduleAtFixedRate(...);
* f.cancel(/* mayInterrupt= * / false);
* <p>
*
* Failure semantics
* -----------------
* - If a periodic task THROWS, subsequent runs are suppressed and the
* ScheduledFuture's get() will rethrow. ALWAYS catch inside the task
* if you want it to keep running.
* <p>
*
* Java 21
* -------
* - You can pass a virtual-thread factory to the scheduler if you want
* each scheduled run to execute on a virtual thread:
* <p>
*
* Executors.newScheduledThreadPool(1, Thread.ofVirtual().factory());
*/
public class ScheduledExecutorDemo {
public static void main(String[] args) throws Exception {
try (ScheduledExecutorService ses = Executors.newScheduledThreadPool(2)) {
section("1) schedule — one-shot delay");
long t0 = System.currentTimeMillis();
ScheduledFuture<String> one = ses.schedule(
() -> "fired @ " + (System.currentTimeMillis() - t0) + " ms",
100, TimeUnit.MILLISECONDS);
System.out.println(one.get());
section("2) scheduleAtFixedRate — every 80ms regardless of duration");
int[] runs = { 0 };
long start = System.currentTimeMillis();
ScheduledFuture<?> tick = ses.scheduleAtFixedRate(() -> {
runs[0]++;
System.out.println(" tick #" + runs[0] + " at " + (System.currentTimeMillis() - start) + "ms");
}, 0, 80, TimeUnit.MILLISECONDS);
Thread.sleep(350);
tick.cancel(false);
System.out.println("ran " + runs[0] + " times");
section("3) scheduleWithFixedDelay — wait AFTER each run");
long s2 = System.currentTimeMillis();
ScheduledFuture<?> tock = ses.scheduleWithFixedDelay(() -> {
System.out.println(" tock at " + (System.currentTimeMillis() - s2) + "ms");
sleep(40); // pretend the run takes work
}, 0, 80, TimeUnit.MILLISECONDS);
Thread.sleep(400);
tock.cancel(false);
section("4) Failure suppresses further runs unless you catch");
int[] fragileRuns = { 0 };
ScheduledFuture<?> fragile = ses.scheduleAtFixedRate(() -> {
fragileRuns[0]++;
if (fragileRuns[0] == 2) throw new RuntimeException("boom");
System.out.println(" fragile #" + fragileRuns[0]);
}, 0, 50, TimeUnit.MILLISECONDS);
Thread.sleep(300);
System.out.println("fragile runs total = " + fragileRuns[0] + " (should be 2 — failure killed it)");
try { fragile.get(50, TimeUnit.MILLISECONDS); }
catch (Exception e) { System.out.println("future rethrew: " + e.getClass().getSimpleName()); }
section("5) Catch inside the task to keep running");
int[] robustRuns = { 0 };
ScheduledFuture<?> robust = ses.scheduleAtFixedRate(() -> {
try {
robustRuns[0]++;
if (robustRuns[0] == 2) throw new RuntimeException("controlled");
System.out.println(" robust #" + robustRuns[0]);
} catch (Throwable t) {
System.out.println(" caught locally: " + t.getMessage());
}
}, 0, 50, TimeUnit.MILLISECONDS);
Thread.sleep(300);
robust.cancel(false);
System.out.println("robust runs = " + robustRuns[0] + " (continued past failure)");
section("done");
} // shutdown via AutoCloseable
}
private static void sleep(long ms) {
try { Thread.sleep(ms); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); }
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}