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