1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.util.concurrent;
18
19 import net.jcip.annotations.ThreadSafe;
20
21 import java.util.concurrent.Callable;
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.Future;
24 import java.util.concurrent.FutureTask;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27 import java.util.concurrent.atomic.AtomicMarkableReference;
28
29
30
31
32
33
34
35
36
37
38
39 @ThreadSafe public class SettableFuture<T> implements Future<T> {
40 private volatile AtomicMarkableReference<T> ref = new AtomicMarkableReference<T>(null, false);
41 private final CountDownLatch latch = new CountDownLatch(1);
42
43 public void set(final T value) {
44 final boolean[] mark = new boolean[1];
45 while (true) {
46 final T oldValue = ref.get(mark);
47 if (mark[0]) {
48 if (!equals(oldValue, value)) {
49 throw new IllegalArgumentException("cannot change value after it has been set");
50 }
51 return;
52 }
53 if (!ref.compareAndSet(null, value, false, true)) {
54 continue;
55 }
56 latch.countDown();
57 return;
58 }
59 }
60
61 public T get() throws InterruptedException {
62 latch.await();
63 return ref.getReference();
64 }
65
66 public T get(final long timeout, final TimeUnit unit) throws InterruptedException, TimeoutException {
67 if (!latch.await(timeout, unit)) {
68 throw new TimedOutException(timeout, unit);
69 }
70 return ref.getReference();
71 }
72
73 public boolean isDone() {
74 return ref.getReference() != null;
75 }
76
77
78
79 public boolean isCancelled() {
80 return false;
81 }
82
83 public boolean cancel(final boolean mayInterruptIfRunning) {
84 return false;
85 }
86
87 private boolean equals(final T one, final T two) {
88 if (one == null) {
89 return two == null;
90 }
91 return one.equals(two);
92 }
93 }