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 static com.atlassian.util.concurrent.Assertions.notNull;
20  import static com.atlassian.util.concurrent.Functions.fromSupplier;
21  import static com.atlassian.util.concurrent.ManagedLocks.ManagedFactory.managedFactory;
22  import static com.atlassian.util.concurrent.WeakMemoizer.weakMemoizer;
23  
24  import java.util.concurrent.Callable;
25  import java.util.concurrent.locks.Lock;
26  import java.util.concurrent.locks.ReadWriteLock;
27  import java.util.concurrent.locks.ReentrantLock;
28  import java.util.concurrent.locks.ReentrantReadWriteLock;
29  
30  import com.atlassian.util.concurrent.ManagedLock.ReadWrite;
31  
32  /**
33   * Static factory for producing {@link ManagedLock} and {@link ReadWrite}
34   * instances. Also contains factory methods for getting striping functions for
35   * these as well.
36   * <p>
37   * All Parameters and returns values do no allow nulls. All supplied
38   * {@link Function functions} should not allow null values are permit null
39   * returns.
40   * <p>
41   * Several methods take stripe functions. These functions should return the same
42   * value for the life of their input, ie they should be based on immutable
43   * properties of the input value - otherwise the stripe function might point to
44   * a different lock depending on the state of the input.
45   * 
46   * @since 0.0.7
47   */
48  public class ManagedLocks {
49      /**
50       * Get a {@link ManagedLock} that manages the supplied {@link Lock}.
51       * 
52       * @param lock the lock to use.
53       * @return a managed lock
54       */
55      public static @NotNull
56      ManagedLock manage(final @NotNull Lock lock) {
57          return new ManagedLockImpl(lock);
58      }
59  
60      /**
61       * Get a {@link ManagedLock.ReadWrite} that manages the supplied
62       * {@link ReadWriteLock}.
63       * 
64       * @param lock the lock to use.
65       * @return a managed read write lock
66       */
67      public static @NotNull
68      ManagedLock.ReadWrite manageReadWrite(final @NotNull ReadWriteLock lock) {
69          return new ReadWriteManagedLock(lock);
70      }
71  
72      /**
73       * Create a {@link Function} for resolving {@link ManagedLock managed locks}
74       * . The particular lock is resolved using a striping {@link Function} that
75       * is used look up a lock instance. This allows for a finite set of locks to
76       * be used even if the set of T is essentially unbounded. The locks are
77       * stored using weak references so infrequently accessed locks should not
78       * use excess memory.
79       * 
80       * @param <T> the type of the thing used to look up locks
81       * @param <D> the type used to map lock instances
82       * @param stripeFunction to convert the input to the thing used to look up
83       * the individual locks
84       * @param the factory for creating the individual locks
85       * @return a new {@link Function} that provides {@link ManagedLock}
86       * instances that stores created instances with weak references.
87       */
88      public static @NotNull
89      <T, D> Function<T, ManagedLock> weakManagedLockFactory(final @NotNull Function<T, D> stripeFunction, final @NotNull Supplier<Lock> lockSupplier) {
90          final Function<D, ManagedLock> lockFactory = fromSupplier(managedLockFactory(lockSupplier));
91          return managedFactory(weakMemoizer(lockFactory), stripeFunction);
92      }
93  
94      /**
95       * Convenience method that simply calls
96       * {@link ManagedLocks#weakManagedLockFactory(Function, Supplier)} with the
97       * {@link #lockFactory() default lock factory}.
98       * 
99       * @param <T> the type of the thing used to look up locks
100      * @param <D> the type used to map lock instances
101      * @param stripeFunction to convert Ts to Ds.
102      * @see ManagedLocks#weakLockManager(Function, int)
103      */
104     public static @NotNull
105     <T, D> Function<T, ManagedLock> weakManagedLockFactory(final @NotNull Function<T, D> stripeFunction) {
106         return weakManagedLockFactory(stripeFunction, lockFactory());
107     }
108 
109     /**
110      * Convenience method that calls
111      * {@link ManagedLocks#weakManagedLockFactory(Function)} using the
112      * {@link Functions#identity() identity function} for striping, essentially
113      * meaning that unique input will have its own lock.
114      * 
115      * @param <T> the type of the thing used to look up locks
116      * @param <D> the type used to map lock instances
117      * @param stripeFunction to convert Ts to Ds.
118      * @see ManagedLocks#weakLockManager(Function, int)
119      */
120     public static @NotNull
121     <T> Function<T, ManagedLock> weakManagedLockFactory() {
122         return weakManagedLockFactory(Functions.<T> identity());
123     }
124 
125     /**
126      * Create a {@link Function} for resolving {@link ManagedLock.ReadWrite
127      * managed read-write locks}. The particular lock is resolved using a
128      * striping {@link Function} that is used look up a lock instance. This
129      * allows for a finite set of locks to be used even if the set of T is
130      * essentially unbounded. The locks are stored using weak references so
131      * infrequently accessed locks should not use excess memory.
132      * 
133      * @param <T> the type of the thing used to look up locks
134      * @param <D> the type used to map lock instances
135      * @param stripeFunction to convert the input to the thing used to look up
136      * the individual locks
137      * @param the factory for creating the individual locks
138      * @return a new {@link Function} that provides
139      * {@link ManagedLock.ReadWrite} instances that stores created instances
140      * with weak references.
141      */
142     public static @NotNull
143     <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final @NotNull Function<T, D> stripeFunction,
144         final @NotNull Supplier<ReadWriteLock> lockSupplier) {
145         notNull("stripeFunction", stripeFunction);
146         final Function<D, ReadWrite> readWriteManagedLockFactory = fromSupplier(managedReadWriteLockFactory(lockSupplier));
147         final WeakMemoizer<D, ManagedLock.ReadWrite> locks = weakMemoizer(readWriteManagedLockFactory);
148         return new Function<T, ManagedLock.ReadWrite>() {
149             public ManagedLock.ReadWrite get(final T input) {
150                 return locks.get(stripeFunction.get(input));
151             };
152         };
153     }
154 
155     /**
156      * A convenience method for calling
157      * {@link #weakReadWriteManagedLockFactory(Function, Supplier)} that uses
158      * default {@link ReentrantReadWriteLock locks}
159      * 
160      * @param <T> the type of the thing used to look up locks
161      * @param <D> the type used to map lock instances
162      * @param stripeFunction
163      * @return a new {@link Function} that provides
164      * {@link ManagedLock.ReadWrite} instances that stores created instances
165      * with weak references.
166      */
167     public static @NotNull
168     <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final Function<T, D> stripeFunction) {
169         return weakReadWriteManagedLockFactory(stripeFunction, readWriteLockFactory());
170     }
171 
172     /**
173      * A convenience method for calling
174      * {@link #weakReadWriteManagedLockFactory(Function)} that uses the
175      * {@link Functions#identity() identity function} for striping, essentially
176      * meaning that unique input will have its own lock.
177      * 
178      * @param <T> the type of the thing used to look up locks
179      * @param <D> the type used to map lock instances
180      * @return a new {@link Function} that provides
181      * {@link ManagedLock.ReadWrite} instances that stores created instances
182      * with weak references.
183      */
184     public static @NotNull
185     <T> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory() {
186         return weakReadWriteManagedLockFactory(Functions.<T> identity());
187     }
188 
189     /**
190      * A {@link Supplier} of {@link ReentrantLock locks}.
191      * 
192      * @return lock factory
193      */
194     static @NotNull
195     Supplier<Lock> lockFactory() {
196         return new Supplier<Lock>() {
197             public Lock get() {
198                 return new ReentrantLock();
199             }
200         };
201     }
202 
203     /**
204      * A {@link Supplier} of {@link ReentrantReadWriteLock read write locks}.
205      * 
206      * @return lock factory
207      */
208     static @NotNull
209     Supplier<ReadWriteLock> readWriteLockFactory() {
210         return new Supplier<ReadWriteLock>() {
211             public ReadWriteLock get() {
212                 return new ReentrantReadWriteLock();
213             }
214         };
215     }
216 
217     /**
218      * A {@link Supplier} of {@link ManagedLock managed locks}.
219      * 
220      * @return lock factory
221      */
222     static @NotNull
223     Supplier<ManagedLock> managedLockFactory(final @NotNull Supplier<Lock> supplier) {
224         notNull("supplier", supplier);
225         return new Supplier<ManagedLock>() {
226             public ManagedLock get() {
227                 return new ManagedLockImpl(supplier.get());
228             }
229         };
230     }
231 
232     /**
233      * A {@link Supplier} of {@link ManagedLock.ReadWrite managed read write
234      * locks}.
235      * 
236      * @return lock factory
237      */
238     static @NotNull
239     Supplier<ManagedLock.ReadWrite> managedReadWriteLockFactory(final @NotNull Supplier<ReadWriteLock> supplier) {
240         notNull("supplier", supplier);
241         return new Supplier<ManagedLock.ReadWrite>() {
242             public ManagedLock.ReadWrite get() {
243                 return new ReadWriteManagedLock(supplier.get());
244             }
245         };
246     }
247 
248     /**
249      * Implement {@link ReadWrite}
250      */
251     static class ReadWriteManagedLock implements ManagedLock.ReadWrite {
252         private final ManagedLock read;
253         private final ManagedLock write;
254 
255         ReadWriteManagedLock(final ReadWriteLock lock) {
256             notNull("lock", lock);
257             read = new ManagedLockImpl(lock.readLock());
258             write = new ManagedLockImpl(lock.writeLock());
259         }
260 
261         public ManagedLock read() {
262             return read;
263         }
264 
265         public ManagedLock write() {
266             return write;
267         }
268     }
269 
270     static class ManagedFactory<T, D> implements Function<T, ManagedLock> {
271         static final <T, D> ManagedFactory<T, D> managedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
272             return new ManagedFactory<T, D>(lockResolver, stripeFunction);
273         }
274 
275         private final Function<D, ManagedLock> lockResolver;
276         private final Function<T, D> stripeFunction;
277 
278         ManagedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
279             this.lockResolver = notNull("lockResolver", lockResolver);
280             this.stripeFunction = notNull("stripeFunction", stripeFunction);
281         }
282 
283         public ManagedLock get(final T descriptor) {
284             return lockResolver.get(stripeFunction.get(descriptor));
285         };
286     }
287 
288     /**
289      * Default implementation of {@link ManagedLock}
290      * 
291      * @param <T> the input type
292      * @param <D> the type used for the internal lock resolution.
293      */
294     static class ManagedLockImpl implements ManagedLock {
295         private final Lock lock;
296 
297         ManagedLockImpl(final @NotNull Lock lock) {
298             this.lock = notNull("lock", lock);
299         }
300 
301         public <R> R withLock(final Supplier<R> supplier) {
302             lock.lock();
303             try {
304                 return supplier.get();
305             } finally {
306                 lock.unlock();
307             }
308         }
309 
310         public <R> R withLock(final Callable<R> callable) throws Exception {
311             lock.lock();
312             try {
313                 return callable.call();
314             } finally {
315                 lock.unlock();
316             }
317         }
318 
319         public void withLock(final Runnable runnable) {
320             lock.lock();
321             try {
322                 runnable.run();
323             } finally {
324                 lock.unlock();
325             }
326         }
327     }
328 
329     // /CLOVER:OFF
330     private ManagedLocks() {
331         throw new AssertionError("cannot instantiate!");
332     }
333     // /CLOVER:ON
334 }