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 lockFactory 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> lockFactory) {
90          final Function<D, ManagedLock> lockFunction = fromSupplier(managedLockFactory(lockFactory));
91          return managedFactory(weakMemoizer(lockFunction), stripeFunction);
92      }
93  
94      /**
95       * Convenience method that simply calls
96       * {@link #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 #weakManagedLockFactory(Function, Supplier)
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      * @see #weakManagedLockFactory(Function, Supplier)
117      */
118     public static @NotNull
119     <T> Function<T, ManagedLock> weakManagedLockFactory() {
120         return weakManagedLockFactory(Functions.<T> identity());
121     }
122 
123     /**
124      * Create a {@link Function} for resolving {@link ManagedLock.ReadWrite
125      * managed read-write locks}. The particular lock is resolved using a
126      * striping {@link Function} that is used look up a lock instance. This
127      * allows for a finite set of locks to be used even if the set of T is
128      * essentially unbounded. The locks are stored using weak references so
129      * infrequently accessed locks should not use excess memory.
130      * 
131      * @param <T> the type of the thing used to look up locks
132      * @param <D> the type used to map lock instances
133      * @param stripeFunction to convert the input to the thing used to look up
134      * the individual locks
135      * @param lockFactory the factory for creating the individual locks
136      * @return a new {@link Function} that provides
137      * {@link ManagedLock.ReadWrite} instances that stores created instances
138      * with weak references.
139      */
140     public static @NotNull
141     <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final @NotNull Function<T, D> stripeFunction,
142         final @NotNull Supplier<ReadWriteLock> lockFactory) {
143         notNull("stripeFunction", stripeFunction);
144         final Function<D, ReadWrite> readWriteManagedLockFactory = fromSupplier(managedReadWriteLockFactory(lockFactory));
145         final WeakMemoizer<D, ManagedLock.ReadWrite> locks = weakMemoizer(readWriteManagedLockFactory);
146         return new Function<T, ManagedLock.ReadWrite>() {
147             public ManagedLock.ReadWrite get(final T input) {
148                 return locks.get(stripeFunction.get(input));
149             };
150         };
151     }
152 
153     /**
154      * A convenience method for calling
155      * {@link #weakReadWriteManagedLockFactory(Function, Supplier)} that uses
156      * default {@link ReentrantReadWriteLock locks}
157      * 
158      * @param <T> the type of the thing used to look up locks
159      * @param <D> the type used to map lock instances
160      * @param stripeFunction
161      * @return a new {@link Function} that provides
162      * {@link ManagedLock.ReadWrite} instances that stores created instances
163      * with weak references.
164      */
165     public static @NotNull
166     <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final Function<T, D> stripeFunction) {
167         return weakReadWriteManagedLockFactory(stripeFunction, readWriteLockFactory());
168     }
169 
170     /**
171      * A convenience method for calling
172      * {@link #weakReadWriteManagedLockFactory(Function)} that uses the
173      * {@link Functions#identity() identity function} for striping, essentially
174      * meaning that unique input will have its own lock.
175      * 
176      * @param <T> the type of the thing used to look up locks
177      * @return a new {@link Function} that provides the appropriate
178      * {@link ReadWrite} for the argument {@link ManagedLock.ReadWrite}
179      * instances that stores created instances with weak references.
180      */
181     public static @NotNull
182     <T> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory() {
183         return weakReadWriteManagedLockFactory(Functions.<T> identity());
184     }
185 
186     /**
187      * A {@link Supplier} of {@link ReentrantLock locks}.
188      * 
189      * @return lock factory
190      */
191     static @NotNull
192     Supplier<Lock> lockFactory() {
193         return new Supplier<Lock>() {
194             public Lock get() {
195                 return new ReentrantLock();
196             }
197         };
198     }
199 
200     /**
201      * A {@link Supplier} of {@link ReentrantReadWriteLock read write locks}.
202      * 
203      * @return lock factory
204      */
205     static @NotNull
206     Supplier<ReadWriteLock> readWriteLockFactory() {
207         return new Supplier<ReadWriteLock>() {
208             public ReadWriteLock get() {
209                 return new ReentrantReadWriteLock();
210             }
211         };
212     }
213 
214     /**
215      * A {@link Supplier} of {@link ManagedLock managed locks}.
216      * 
217      * @return lock factory
218      */
219     static @NotNull
220     Supplier<ManagedLock> managedLockFactory(final @NotNull Supplier<Lock> supplier) {
221         notNull("supplier", supplier);
222         return new Supplier<ManagedLock>() {
223             public ManagedLock get() {
224                 return new ManagedLockImpl(supplier.get());
225             }
226         };
227     }
228 
229     /**
230      * A {@link Supplier} of {@link ManagedLock.ReadWrite managed read write
231      * locks}.
232      * 
233      * @return lock factory
234      */
235     static @NotNull
236     Supplier<ManagedLock.ReadWrite> managedReadWriteLockFactory(final @NotNull Supplier<ReadWriteLock> supplier) {
237         notNull("supplier", supplier);
238         return new Supplier<ManagedLock.ReadWrite>() {
239             public ManagedLock.ReadWrite get() {
240                 return new ReadWriteManagedLock(supplier.get());
241             }
242         };
243     }
244 
245     /**
246      * Implement {@link ReadWrite}
247      */
248     static class ReadWriteManagedLock implements ManagedLock.ReadWrite {
249         private final ManagedLock read;
250         private final ManagedLock write;
251 
252         ReadWriteManagedLock(final ReadWriteLock lock) {
253             notNull("lock", lock);
254             read = new ManagedLockImpl(lock.readLock());
255             write = new ManagedLockImpl(lock.writeLock());
256         }
257 
258         public ManagedLock read() {
259             return read;
260         }
261 
262         public ManagedLock write() {
263             return write;
264         }
265     }
266 
267     static class ManagedFactory<T, D> implements Function<T, ManagedLock> {
268         static final <T, D> ManagedFactory<T, D> managedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
269             return new ManagedFactory<T, D>(lockResolver, stripeFunction);
270         }
271 
272         private final Function<D, ManagedLock> lockResolver;
273         private final Function<T, D> stripeFunction;
274 
275         ManagedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
276             this.lockResolver = notNull("lockResolver", lockResolver);
277             this.stripeFunction = notNull("stripeFunction", stripeFunction);
278         }
279 
280         public ManagedLock get(final T descriptor) {
281             return lockResolver.get(stripeFunction.get(descriptor));
282         };
283     }
284 
285     /**
286      * Default implementation of {@link ManagedLock}
287      * 
288      * @param <T> the input type
289      * @param <D> the type used for the internal lock resolution.
290      */
291     static class ManagedLockImpl implements ManagedLock {
292         private final Lock lock;
293 
294         ManagedLockImpl(final @NotNull Lock lock) {
295             this.lock = notNull("lock", lock);
296         }
297 
298         public <R> R withLock(final Supplier<R> supplier) {
299             lock.lock();
300             try {
301                 return supplier.get();
302             } finally {
303                 lock.unlock();
304             }
305         }
306 
307         public <R> R withLock(final Callable<R> callable) throws Exception {
308             lock.lock();
309             try {
310                 return callable.call();
311             } finally {
312                 lock.unlock();
313             }
314         }
315 
316         public void withLock(final Runnable runnable) {
317             lock.lock();
318             try {
319                 runnable.run();
320             } finally {
321                 lock.unlock();
322             }
323         }
324     }
325 
326     // /CLOVER:OFF
327     private ManagedLocks() {
328         throw new AssertionError("cannot instantiate!");
329     }
330     // /CLOVER:ON
331 }