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.Immutable;
20  
21  import java.util.concurrent.TimeUnit;
22  
23  /**
24   * Used to calculate elapsed time for timeouts from when it is created when successively calling
25   * blocking methods. Always converts to nanoseconds.
26   * <p>
27   * Usage:
28   * 
29   * <pre>
30   * Timeout timeout = Timeout.getNanosTimeout(1, TimeUnit.SECONDS);
31   * String str = futureString.get(timeout.getTime(), timeout.getUnit());
32   * Integer num = futureInt.get(timeout.getTime(), timeout.getUnit());
33   * </pre>
34   * 
35   * where if the first call takes quarter of a second, the second call is passed the equivalent of
36   * three-quarters of a second.
37   */
38  @Immutable public class Timeout {
39  
40      private static final TimeSupplier NANO_SUPPLIER = new TimeSupplier() {
41          public long currentTime() {
42              return System.nanoTime();
43          };
44  
45          public TimeUnit precision() {
46              return TimeUnit.NANOSECONDS;
47          };
48      };
49  
50      private static final TimeSupplier MILLIS_SUPPLIER = new TimeSupplier() {
51          public long currentTime() {
52              return System.currentTimeMillis();
53          };
54  
55          public TimeUnit precision() {
56              return TimeUnit.MILLISECONDS;
57          };
58      };
59  
60      /**
61       * Get a {@link Timeout} that uses nanosecond precision. The accuracy will depend on the
62       * accuracy of {@link System#nanoTime()}.
63       * 
64       * @param time the maximum time to wait for the lock
65       * @param unit the time unit of the <tt>time</tt> argument.
66       * @return timeout with {@link TimeUnit#NANOSECONDS} precision.
67       */
68      public static Timeout getNanosTimeout(final long time, final TimeUnit unit) {
69          return new Timeout(time, unit, NANO_SUPPLIER);
70      }
71  
72      /**
73       * Get a {@link Timeout} that uses nanosecond precision. The accuracy will depend on the
74       * accuracy of {@link System#nanoTime()}.
75       * 
76       * @param time the maximum time to wait for the lock
77       * @param unit the time unit of the <tt>time</tt> argument.
78       * @return timeout with {@link TimeUnit#NANOSECONDS} precision.
79       */
80      public static Timeout getMillisTimeout(final long time, final TimeUnit unit) {
81          return new Timeout(time, unit, MILLIS_SUPPLIER);
82      }
83  
84      private final long created;
85      private final long time;
86      private final TimeSupplier supplier;
87  
88      Timeout(final long time, final TimeUnit unit, final TimeSupplier supplier) {
89          created = supplier.currentTime();
90          this.supplier = supplier;
91          this.time = this.supplier.precision().convert(time, unit);
92      }
93  
94      public long getTime() {
95          return (created + time) - supplier.currentTime();
96      }
97  
98      public TimeUnit getUnit() {
99          return supplier.precision();
100     }
101 
102     /**
103      * Has this timeout expired
104      * 
105      * @return
106      */
107     public boolean isExpired() {
108         return getTime() <= 0;
109     }
110 
111     /**
112      * Supply time and precision to a {@link Timeout}.
113      */
114     interface TimeSupplier {
115         long currentTime();
116 
117         TimeUnit precision();
118     }
119 }