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 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   * {@link SettableFuture} is a {@link Future} implementation where the
31   * responsibility for producing the result is external to the future instance,
32   * unlike {@link FutureTask} where the future holds the operation (a
33   * {@link Callable} or {@link Runnable} instance) and the first thread that
34   * calls {@link FutureTask#run()} executes the operation.
35   * <p>
36   * This is useful in situations where all the inputs may not be available at
37   * construction time.
38   * <p>
39   * This class does not support cancellation.
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              // /CLOVER:OFF
57              if (!ref.compareAndSet(null, value, false, true)) {
58                  continue;
59              }
60              // /CLOVER:ON
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      // not cancellable
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  }