[52] | 1 | package geniusweb.protocol.session.amop;
|
---|
| 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()} 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()} 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 | }
|
---|