1 | package geniusweb.protocol;
|
---|
2 |
|
---|
3 | import java.util.concurrent.ScheduledThreadPoolExecutor;
|
---|
4 | import java.util.concurrent.TimeUnit;
|
---|
5 | import java.util.concurrent.atomic.AtomicBoolean;
|
---|
6 |
|
---|
7 | /**
|
---|
8 | * Object containing function that will be called exactly once, on demand or at
|
---|
9 | * given deadline.
|
---|
10 | *
|
---|
11 | */
|
---|
12 | public class WillBeCalled {
|
---|
13 | private static volatile ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
|
---|
14 | 2);
|
---|
15 | private final Runnable runnable;
|
---|
16 | private volatile AtomicBoolean done = new AtomicBoolean(false);
|
---|
17 |
|
---|
18 | /**
|
---|
19 | * @param r the runnable that will be run once, either when the user
|
---|
20 | * calls {@link #complete(Void)} or after delayMs, whichever
|
---|
21 | * comes first.
|
---|
22 | * @param delayMs the delay after this will be called anywa (the 'deadline'
|
---|
23 | * in milliseconds. If null, no deadline call will be made
|
---|
24 | * and the user must call {@link #complete(Void)} himself.
|
---|
25 | */
|
---|
26 | public WillBeCalled(Runnable r, Long delayMs) {
|
---|
27 | this.runnable = r;
|
---|
28 | if (delayMs != null) {
|
---|
29 | executor.schedule(() -> complete(), delayMs, TimeUnit.MILLISECONDS);
|
---|
30 | }
|
---|
31 | }
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * Tells the runnable to be executed. Only the first time the function is
|
---|
35 | * run, subsequent calls do nothing. Failures in runnable are NOT caught
|
---|
36 | * here, as they are probably bugs
|
---|
37 | *
|
---|
38 | * We must avoid synchronized here because users may use synchronized blocks
|
---|
39 | * already.
|
---|
40 | */
|
---|
41 | public void complete() {
|
---|
42 | if (!done.compareAndSet(false, true))
|
---|
43 | return;
|
---|
44 | runnable.run();
|
---|
45 | }
|
---|
46 | }
|
---|