-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRunnableInterface.java
More file actions
135 lines (119 loc) · 4.9 KB
/
Copy pathRunnableInterface.java
File metadata and controls
135 lines (119 loc) · 4.9 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
package Phase7_Concurrency.Multithreading;
/**
* java.lang.Runnable
* ------------------
* The simplest description of "a unit of work that can be run by a
* thread." It is a FUNCTIONAL interface with one method:
* <p>
*
* @FunctionalInterface
* public interface Runnable {
* void run();
* }
* <p>
*
* - No arguments
* - No return value
* - No checked exceptions (you must catch / wrap)
* <p>
*
* Why prefer Runnable over extending Thread?
* ------------------------------------------
* 1. SEPARATION OF CONCERNS — describes the WORK without coupling it
* to a Thread.
* 2. COMPOSITION — can be passed to Thread, ExecutorService, Timer,
* ScheduledExecutorService, ForkJoinPool, etc.
* 3. INHERITANCE — you can extend any other class you like.
* 4. LAMBDAS — Runnable r = () -> ...; is concise and capture-friendly.
* <p>
*
* Variants you should know
* ------------------------
* Runnable - void run(), no exceptions, used by Thread / Executor.execute
* Callable<V> - V call() throws Exception. Used by ExecutorService.submit.
* RunnableFuture / FutureTask - Runnable + Future, used internally.
* <p>
*
* Common patterns
* ---------------
* - As a constructor argument: new Thread(runnable).start()
* - As a method argument: executor.submit(runnable)
* - Composing two: Runnable both = () -> { a.run(); b.run(); };
* - Decorating: wrap to log start/stop, time, retry
*/
public class RunnableInterface {
public static void main(String[] args) throws InterruptedException {
section("1) Classic implementation");
Runnable classic = new Runnable() {
@Override public void run() {
System.out.println("classic Runnable on " + Thread.currentThread().getName());
}
};
new Thread(classic, "classic").start();
section("2) Lambda — the modern way");
Runnable lambda = () -> System.out.println("lambda Runnable on " + Thread.currentThread().getName());
new Thread(lambda, "lambda").start();
section("3) Method reference");
Runnable ref = RunnableInterface::work;
new Thread(ref, "ref").start();
Thread.sleep(50); // let the three above run before next demos
section("4) Composing runnables");
Runnable a = () -> System.out.println(" step A");
Runnable b = () -> System.out.println(" step B");
Runnable both = chain(a, b);
new Thread(both, "compose").start();
Thread.sleep(50);
section("5) Decorating a Runnable");
Runnable noisy = decorateWithTiming(() -> {
try { Thread.sleep(80); } catch (InterruptedException ignored) {}
System.out.println(" inside the wrapped task");
}, "noisy");
new Thread(noisy).start();
Thread.sleep(150);
section("6) Runnable cannot throw checked exceptions");
// run() declares no `throws`. You must catch checked exceptions
// and wrap them as runtime exceptions if you want to propagate.
Runnable explodes = () -> {
try {
Thread.sleep(50);
throw new java.io.IOException("checked!");
} catch (Exception e) {
throw new RuntimeException("wrapped", e);
}
};
Thread blew = new Thread(explodes, "blew");
blew.setUncaughtExceptionHandler((t, ex) ->
System.out.println(" caught from " + t.getName() + " -> " + ex.getMessage()));
blew.start();
blew.join();
section("7) Use Runnable with ExecutorService (preview — see ExecutorFramework.java)");
var es = java.util.concurrent.Executors.newFixedThreadPool(2);
es.execute(() -> System.out.println("from pool: " + Thread.currentThread().getName()));
es.execute(() -> System.out.println("from pool: " + Thread.currentThread().getName()));
es.shutdown();
es.awaitTermination(1, java.util.concurrent.TimeUnit.SECONDS);
section("done");
}
private static void work() {
System.out.println("static method ref on " + Thread.currentThread().getName());
}
/** Chain runnables together: first.run(); second.run(); */
private static Runnable chain(Runnable first, Runnable second) {
return () -> { first.run(); second.run(); };
}
/** Wrap any Runnable with timing + tagged log lines. */
private static Runnable decorateWithTiming(Runnable r, String tag) {
return () -> {
long t0 = System.nanoTime();
try { r.run(); }
finally {
long ms = (System.nanoTime() - t0) / 1_000_000;
System.out.println("[" + tag + "] took " + ms + " ms");
}
};
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}