View Javadoc

1   /**
2    * Copyright 2008 Atlassian Pty Ltd 
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0 
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
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   * {@link SettableFuture} is a {@link Future} implementation where the responsibility for producing
31   * the result is external to the future instance, unlike {@link FutureTask} where the future holds
32   * the operation (a {@link Callable} or {@link Runnable} instance) and the first thread that calls
33   * {@link FutureTask#run()} executes the operation.
34   * <p>
35   * This is useful in situations where all the inputs may not be available at construction time.
36   * <p>
37   * This class does not support cancellation.
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      // not cancellable
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  }