View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.concurrent;
33  
34  import java.util.concurrent.TimeUnit;
35  import java.util.concurrent.TimeoutException;
36  import javax.annotation.CheckReturnValue;
37  import javax.annotation.Nonnegative;
38  import javax.annotation.ParametersAreNonnullByDefault;
39  import javax.annotation.concurrent.ThreadSafe;
40  import org.spf4j.base.ExecutionContexts;
41  
42  /**
43   *
44   * @author Zoltan Farkas
45   */
46  @ThreadSafe
47  @ParametersAreNonnullByDefault
48  public interface PermitSupplier {
49  
50    PermitSupplier UNLIMITED = new PermitSupplier() {
51      @Override
52      public boolean tryAcquire(final int nrPermits, final long deadlineNanos) {
53        return true;
54      }
55  
56      @Override
57      public String toString() {
58        return "Unlimited";
59      }
60  
61  
62  
63    };
64  
65    PermitSupplier EMPTY = new PermitSupplier() {
66      @Override
67      public boolean tryAcquire(final int nrPermits, final long deadlineNanos) {
68        return false;
69      }
70  
71      @Override
72      public String toString() {
73        return "Empty";
74      }
75  
76    };
77  
78    public interface Acquisition {
79  
80      Acquisition SUCCESS = new Acquisition() {
81        @Override
82        public boolean isSuccess() {
83          return true;
84        }
85  
86        @Override
87        public long permitAvailableEstimateInNanos() {
88          return 0L;
89        }
90      };
91  
92      static Acquisition failed(final long nanosUntilAvailable) {
93        return new Acquisition() {
94          @Override
95          public boolean isSuccess() {
96            return false;
97          }
98  
99          @Override
100         public long permitAvailableEstimateInNanos() {
101           return nanosUntilAvailable;
102         }
103       };
104     }
105 
106     /**
107      * @return true is permit acquisition request successful. false otherwise.
108      */
109     boolean isSuccess();
110 
111     /**
112      * @return if acquisition not successful the number of nanos in which permits will be available. -1L if N/A
113      */
114     long permitAvailableEstimateInNanos();
115   }
116 
117   /**
118    * Acquire one permit.
119    *
120    * @param timeout time to wait for permit to become available.
121    * @param unit units of time.
122    * @throws InterruptedException - operation interrupted.
123    * @throws TimeoutException - timed out.
124    */
125   default void acquire(final long timeout, final TimeUnit unit)
126           throws InterruptedException, TimeoutException {
127     acquire(1, timeout, unit);
128   }
129 
130   /**
131    * Acquire a arbitrary number of permits.
132    *
133    * @param nrPermits - numer of permits to acquire.
134    * @param timeout - time to wait for permit to become available.
135    * @param unit - units of time.
136    * @throws InterruptedException - operation interrupted.
137    * @throws TimeoutException - timed out.
138    */
139   default void acquire(final int nrPermits, @Nonnegative final long timeout, final TimeUnit unit)
140           throws InterruptedException, TimeoutException {
141     if (!tryAcquire(nrPermits, timeout, unit)) {
142       throw new TimeoutException("Cannot acquire timeout after " + timeout + " " + unit);
143     }
144   }
145 
146   /**
147    * try to acquire a permit.
148    *
149    * @param timeout time to wait for permit to become available.
150    * @param unit units of time.
151    * @return true if permit acquired, false if timed out.
152    * @throws InterruptedException - operation interrupted.
153    */
154   @CheckReturnValue
155   default boolean tryAcquire(@Nonnegative final long timeout, final TimeUnit unit)
156           throws InterruptedException {
157     return tryAcquire(1, timeout, unit);
158   }
159 
160   /**
161    * try to acquire a number of permits.
162    *
163    * @param nrPermits number of permits to acquire.
164    * @param timeout time to wait for permits to become available.
165    * @param unit units of time.
166    * @return true if permits acquired, false if timed out.
167    * @throws InterruptedException - operation interrupted.
168    */
169   @CheckReturnValue
170   default boolean tryAcquire(@Nonnegative final int nrPermits, @Nonnegative final long timeout, final TimeUnit unit)
171           throws InterruptedException {
172     if (timeout < 0) {
173       throw new IllegalArgumentException("Invalid timeout " + timeout + ' ' + unit);
174     }
175     return tryAcquire(nrPermits, ExecutionContexts.computeDeadline(timeout, unit));
176   }
177 
178   @CheckReturnValue
179   boolean tryAcquire(@Nonnegative int nrPermits, long deadlineNanos) throws InterruptedException;
180 
181 
182   @CheckReturnValue
183   default Acquisition tryAcquireEx(@Nonnegative final int nrPermits,
184           @Nonnegative final long timeout, final TimeUnit unit)
185           throws InterruptedException {
186     if (timeout < 0) {
187       throw new IllegalArgumentException("Invalid timeout " + timeout + ' ' + unit);
188     }
189     return tryAcquireEx(nrPermits, ExecutionContexts.computeDeadline(timeout, unit));
190   }
191 
192   @CheckReturnValue
193   default Acquisition tryAcquireEx(@Nonnegative final int nrPermits, final long deadlineNanos)
194           throws InterruptedException {
195     boolean  res = tryAcquire(nrPermits, deadlineNanos);
196     if (res) {
197       return Acquisition.SUCCESS;
198     } else {
199       return Acquisition.failed(-1L);
200     }
201   }
202 
203 
204   /**
205    * @param nrPermits
206    * @return true if at least one permit is added.
207    */
208   default boolean addPermits(final int nrPermits) {
209     return false;
210   }
211 
212   default Semaphore toSemaphore() {
213     return new Semaphore() {
214       @Override
215       public void release(final int nrPermits) {
216         // nothing to release.
217       }
218 
219       @Override
220       public boolean tryAcquire(final int nrPermits, final long timeout, final TimeUnit unit)
221               throws InterruptedException {
222         return PermitSupplier.this.tryAcquire(nrPermits, timeout, unit);
223       }
224 
225       @Override
226       public boolean tryAcquire(final long timeout, final TimeUnit unit) throws InterruptedException {
227         return PermitSupplier.this.tryAcquire(timeout, unit);
228       }
229 
230       @Override
231       public void acquire(final int nrPermits, final long timeout, final TimeUnit unit)
232               throws InterruptedException, TimeoutException {
233         PermitSupplier.this.acquire(nrPermits, timeout, unit);
234       }
235 
236       @Override
237       public void acquire(final long timeout, final TimeUnit unit) throws InterruptedException, TimeoutException {
238         PermitSupplier.this.acquire(timeout, unit);
239       }
240 
241       @Override
242       public boolean tryAcquire(final int nrPermits, final long deadlineNanos) throws InterruptedException {
243         return PermitSupplier.this.tryAcquire(nrPermits, deadlineNanos);
244       }
245 
246     };
247   }
248 
249 }