View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.concurrent.locks;
18  
19  import java.util.Objects;
20  import java.util.concurrent.locks.Lock;
21  import java.util.concurrent.locks.ReadWriteLock;
22  import java.util.concurrent.locks.ReentrantLock;
23  import java.util.concurrent.locks.ReentrantReadWriteLock;
24  import java.util.concurrent.locks.StampedLock;
25  import java.util.function.Supplier;
26  
27  import org.apache.commons.lang3.builder.AbstractSupplier;
28  import org.apache.commons.lang3.function.Failable;
29  import org.apache.commons.lang3.function.FailableConsumer;
30  import org.apache.commons.lang3.function.FailableFunction;
31  import org.apache.commons.lang3.function.Suppliers;
32  
33  /**
34   * Combines the monitor and visitor pattern to work with {@link Lock}s as an alternative to synchronization.
35   * <p>
36   * The read and write methods use the locks supplied by the visitor. A {@link ReentrantLockVisitor} uses one exclusive lock for both methods.
37   * A {@link ReadWriteLockVisitor} uses the underlying read and write locks, while a {@link StampedLockVisitor} uses its read and write
38   * {@link Lock} views. Read operations may run concurrently only when the supplied lock supports shared reads.
39   * </p>
40   * <p>
41   * For example, to use this class with a {@link ReentrantLock}:
42   * </p>
43   * <ol>
44   * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a
45   * {@link LockingVisitors.ReentrantLockVisitor}
46   * </li>
47   * <li>To access the protected object, create a {@link FailableConsumer} lambda. The consumer will receive the object as a parameter while the visitor holds the
48   * lock. Then call
49   * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or
50   * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.
51   * </li>
52   * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call
53   * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or
54   * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}.
55   * </li>
56   * </ol>
57   * <p>
58   * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}.
59   * </p>
60   *
61   * <pre>{@code
62   *   public class SimpleLogger1 {
63   *
64   *     private final ReentrantLockVisitor<PrintStream> lock;
65   *     private final PrintStream ps;
66   *
67   *     public SimpleLogger(OutputStream out) {
68   *         ps = new PrintStream(out);
69   *         lock = LockingVisitors.reentrantLockVisitor(ps);
70   *     }
71   *
72   *     public void log(String message) {
73   *         lock.acceptWriteLocked(ps -> ps.println(message));
74   *     }
75   *
76   *     public void log(byte[] buffer) {
77   *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
78   *     }
79   * }
80   * }
81   * </pre>
82   *
83   * <p>
84   * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}.
85   * </p>
86   *
87   * <pre>{@code
88   *   public class SimpleLogger2 {
89   *
90   *     private final ReadWriteLockVisitor<PrintStream> lock;
91   *     private final PrintStream ps;
92   *
93   *     public SimpleLogger(OutputStream out) {
94   *         ps = new PrintStream(out);
95   *         lock = LockingVisitors.readWriteLockVisitor(ps);
96   *     }
97   *
98   *     public void log(String message) {
99   *         lock.acceptWriteLocked(ps -> ps.println(message));
100  *     }
101  *
102  *     public void log(byte[] buffer) {
103  *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
104  *     }
105  * }
106  * }
107  * </pre>
108  *
109  * <p>
110  * Example 3: A thread safe logger class using a {@link StampedLock}.
111  * </p>
112  *
113  * <pre>{@code
114  *   public class SimpleLogger3 {
115  *
116  *     private final StampedLockVisitor<PrintStream> lock;
117  *     private final PrintStream ps;
118  *
119  *     public SimpleLogger(OutputStream out) {
120  *         ps = new PrintStream(out);
121  *         lock = LockingVisitors.stampedLockVisitor(ps);
122  *     }
123  *
124  *     public void log(String message) {
125  *         lock.acceptWriteLocked(ps -> ps.println(message));
126  *     }
127  *
128  *     public void log(byte[] buffer) {
129  *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
130  *     }
131  * }
132  * }
133  * </pre>
134  *
135  * @since 3.11
136  */
137 public class LockingVisitors {
138 
139     /**
140      * Wraps a domain object and a lock for access by lambdas.
141      *
142      * @param <O> The wrapped object type.
143      * @param <L> The wrapped lock type.
144      * @see LockingVisitors
145      */
146     public static class LockVisitor<O, L> {
147 
148         /**
149          * Builds {@link LockVisitor} instances.
150          *
151          * @param <O> The wrapped object type.
152          * @param <L> The wrapped lock type.
153          * @param <B> The builder type.
154          * @since 3.18.0
155          */
156         public static class LVBuilder<O, L, B extends LVBuilder<O, L, B>> extends AbstractSupplier<LockVisitor<O, L>, B, RuntimeException> {
157 
158             /**
159              * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or
160              * {@link ReadWriteLock}.
161              */
162             L lock;
163 
164             /**
165              * The guarded object.
166              */
167             O object;
168 
169             /**
170              * Supplies the lock used by read methods.
171              */
172             private Supplier<Lock> readLockSupplier;
173 
174             /**
175              * Supplies the lock used by write methods.
176              */
177             private Supplier<Lock> writeLockSupplier;
178 
179             /**
180              * Constructs a new instance.
181              */
182             public LVBuilder() {
183                 // empty
184             }
185 
186             @Override
187             public LockVisitor<O, L> get() {
188                 return new LockVisitor<>(this);
189             }
190 
191             Supplier<Lock> getReadLockSupplier() {
192                 return readLockSupplier;
193             }
194 
195 
196             Supplier<Lock> getWriteLockSupplier() {
197                 return writeLockSupplier;
198             }
199 
200             /**
201              * Sets the underlying lock returned by {@link LockVisitor#getLock()}.
202              *
203              * @param lock The lock.
204              * @return {@code this} instance.
205              */
206             public B setLock(final L lock) {
207                 this.lock = lock;
208                 return asThis();
209             }
210 
211             /**
212              * Sets the resource.
213              *
214              * @param object The resource.
215              * @return {@code this} instance.
216              */
217             public B setObject(final O object) {
218                 this.object = object;
219                 return asThis();
220             }
221 
222             /**
223              * Sets the supplier of the lock used by read methods.
224              *
225              * @param readLockSupplier Supplies the read lock.
226              * @return {@code this} instance.
227              */
228             public B setReadLockSupplier(final Supplier<Lock> readLockSupplier) {
229                 this.readLockSupplier = readLockSupplier;
230                 return asThis();
231             }
232 
233             /**
234              * Sets the supplier of the lock used by write methods.
235              *
236              * @param writeLockSupplier Supplies the write lock.
237              * @return {@code this} instance.
238              */
239             public B setWriteLockSupplier(final Supplier<Lock> writeLockSupplier) {
240                 this.writeLockSupplier = writeLockSupplier;
241                 return asThis();
242             }
243         }
244 
245         /**
246          * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or
247          * {@link ReadWriteLock}.
248          */
249         private final L lock;
250 
251         /**
252          * The guarded object.
253          */
254         private final O object;
255 
256         /**
257          * Supplies the lock used by read methods.
258          */
259         private final Supplier<Lock> readLockSupplier;
260 
261         /**
262          * Supplies the lock used by write methods.
263          */
264         private final Supplier<Lock> writeLockSupplier;
265 
266         /**
267          * Constructs an instance from a builder.
268          *
269          * @param builder The builder.
270          */
271         private LockVisitor(final LVBuilder<O, L, ?> builder) {
272             this.object = Objects.requireNonNull(builder.object, "object");
273             this.lock = Objects.requireNonNull(builder.lock, "lock");
274             this.readLockSupplier = Objects.requireNonNull(builder.readLockSupplier, "readLockSupplier");
275             this.writeLockSupplier = Objects.requireNonNull(builder.writeLockSupplier, "writeLockSupplier");
276         }
277 
278         /**
279          * Constructs an instance.
280          *
281          * @param object The object to guard.
282          * @param lock The locking object.
283          * @param readLockSupplier Supplies the lock used by read methods.
284          * @param writeLockSupplier Supplies the lock used by write methods.
285          */
286         protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) {
287             this.object = Objects.requireNonNull(object, "object");
288             this.lock = Objects.requireNonNull(lock, "lock");
289             this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier");
290             this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier");
291         }
292 
293         /**
294          * Invokes the consumer while holding the lock supplied for read operations.
295          * The lock is released in a {@code finally} block after the consumer returns or throws. Whether other readers can proceed concurrently depends on the
296          * supplied lock.
297          *
298          * @param consumer The consumer of the guarded object.
299          * @see #acceptWriteLocked(FailableConsumer)
300          * @see #applyReadLocked(FailableFunction)
301          */
302         public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
303             lockAcceptUnlock(readLockSupplier, consumer);
304         }
305 
306         /**
307          * Invokes the consumer while holding the lock supplied for write operations.
308          * The lock is released in a {@code finally} block after the consumer returns or throws.
309          *
310          * @param consumer The consumer of the guarded object.
311          * @see #acceptReadLocked(FailableConsumer)
312          * @see #applyWriteLocked(FailableFunction)
313          */
314         public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
315             lockAcceptUnlock(writeLockSupplier, consumer);
316         }
317 
318         /**
319          * Applies the function while holding the lock supplied for read operations.
320          * The lock is released in a {@code finally} block after the function returns or throws. Whether other readers can proceed concurrently depends on the
321          * supplied lock.
322          *
323          * @param <T> The result type.
324          * @param function The function applied to the guarded object.
325          * @return The function result.
326          * @throws NullPointerException Thrown if the lock supplier is null or returns null.
327          * @see #acceptReadLocked(FailableConsumer)
328          * @see #applyWriteLocked(FailableFunction)
329          */
330         public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
331             return lockApplyUnlock(readLockSupplier, function);
332         }
333 
334         /**
335          * Applies the function while holding the lock supplied for write operations.
336          * The lock is released in a {@code finally} block after the function returns or throws.
337          *
338          * @param <T> The result type.
339          * @param function The function applied to the guarded object.
340          * @return The function result.
341          * @throws NullPointerException Thrown if the lock supplier is null or returns null.
342          * @see #acceptWriteLocked(FailableConsumer)
343          * @see #applyReadLocked(FailableFunction)
344          */
345         public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
346             return lockApplyUnlock(writeLockSupplier, function);
347         }
348 
349         /**
350          * Gets the lock.
351          *
352          * @return The lock.
353          */
354         public L getLock() {
355             return lock;
356         }
357 
358         /**
359          * Gets the guarded object.
360          *
361          * @return The object.
362          */
363         public O getObject() {
364             return object;
365         }
366 
367         /**
368          * Implements {@link #acceptReadLocked(FailableConsumer)} and
369          * {@link #acceptWriteLocked(FailableConsumer)}.
370          *
371          * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view.
372          * @param consumer The consumer of the guarded object.
373          * @see #acceptReadLocked(FailableConsumer)
374          * @see #acceptWriteLocked(FailableConsumer)
375          */
376         protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) {
377             final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
378             lock.lock();
379             try {
380                 Failable.accept(consumer, object);
381             } finally {
382                 lock.unlock();
383             }
384         }
385 
386         /**
387          * Implements {@link #applyReadLocked(FailableFunction)} and
388          * {@link #applyWriteLocked(FailableFunction)}.
389          *
390          * @param <T> The result type.
391          * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view.
392          * @param function The function applied to the guarded object.
393          * @return The function result.
394          * @throws NullPointerException Thrown if the lock supplier is null or returns null.
395          * @see #applyReadLocked(FailableFunction)
396          * @see #applyWriteLocked(FailableFunction)
397          */
398         protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) {
399             final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
400             lock.lock();
401             try {
402                 return Failable.apply(function, object);
403             } finally {
404                 lock.unlock();
405             }
406         }
407 
408     }
409 
410     /**
411      * Wraps a {@link ReadWriteLock} and object to protect. Read methods use {@link ReadWriteLock#readLock()}, and write methods use
412      * {@link ReadWriteLock#writeLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
413      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
414      * holds the lock while the consumer or function is called.
415      *
416      * @param <O> The type of the object to protect.
417      * @see LockingVisitors#create(Object, ReadWriteLock)
418      */
419     public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> {
420 
421         /**
422          * Builds {@link LockVisitor} instances.
423          *
424          * @param <O> The wrapped object type.
425          * @since 3.18.0
426          */
427         public static class Builder<O> extends LVBuilder<O, ReadWriteLock, Builder<O>> {
428 
429             /**
430              * Constructs a new instance.
431              */
432             public Builder() {
433                 // empty
434             }
435 
436             @Override
437             public ReadWriteLockVisitor<O> get() {
438                 return new ReadWriteLockVisitor<>(this);
439             }
440 
441             @Override
442             public Builder<O> setLock(final ReadWriteLock readWriteLock) {
443                 setReadLockSupplier(readWriteLock::readLock);
444                 setWriteLockSupplier(readWriteLock::writeLock);
445                 return super.setLock(readWriteLock);
446             }
447         }
448 
449         /**
450          * Creates a new builder.
451          *
452          * @param <O> The wrapped object type.
453          * @return A new builder.
454          * @since 3.18.0
455          */
456         public static <O> Builder<O> builder() {
457             return new Builder<>();
458         }
459 
460         /**
461          * Constructs a new instance from a builder.
462          *
463          * @param builder A builder.
464          */
465         private ReadWriteLockVisitor(final Builder<O> builder) {
466             super(builder);
467         }
468 
469         /**
470          * Creates a new instance with the given object and lock.
471          *
472          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
473          * @param readWriteLock The lock to use.
474          * @see LockingVisitors
475          */
476         protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) {
477             super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock);
478         }
479 
480     }
481 
482     /**
483      * Wraps a {@link ReentrantLock} and object to protect. Both read and write methods acquire the same exclusive lock.
484      * To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
485      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
486      * holds the lock while the consumer or function is called.
487      *
488      * @param <O> The type of the object to protect.
489      * @see LockingVisitors#reentrantLockVisitor(Object)
490      * @since 3.18.0
491      */
492     public static class ReentrantLockVisitor<O> extends LockVisitor<O, ReentrantLock> {
493 
494         /**
495          * Builds {@link LockVisitor} instances.
496          *
497          * @param <O> The wrapped object type.
498          * @since 3.18.0
499          */
500         public static class Builder<O> extends LVBuilder<O, ReentrantLock, Builder<O>> {
501 
502             /**
503              * Constructs a new instance.
504              */
505             public Builder() {
506                 // empty
507             }
508 
509             @Override
510             public ReentrantLockVisitor<O> get() {
511                 return new ReentrantLockVisitor<>(this);
512             }
513 
514 
515             @Override
516             public Builder<O> setLock(final ReentrantLock reentrantLock) {
517                 setReadLockSupplier(() -> reentrantLock);
518                 setWriteLockSupplier(() -> reentrantLock);
519                 return super.setLock(reentrantLock);
520             }
521         }
522 
523         /**
524          * Creates a new builder.
525          *
526          * @param <O> The wrapped object type.
527          * @return A new builder.
528          * @since 3.18.0
529          */
530         public static <O> Builder<O> builder() {
531             return new Builder<>();
532         }
533 
534         /**
535          * Constructs a new instance from a builder.
536          *
537          * @param builder A builder.
538          */
539         private ReentrantLockVisitor(final Builder<O> builder) {
540             super(builder);
541         }
542 
543 
544         /**
545          * Creates a new instance with the given object and lock.
546          * <p>
547          * This visitor uses the given {@link ReentrantLock} for both read and write methods; both acquire it exclusively.
548          * </p>
549          *
550          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
551          * @param reentrantLock The lock to use.
552          * @see LockingVisitors
553          */
554         protected ReentrantLockVisitor(final O object, final ReentrantLock reentrantLock) {
555             super(object, reentrantLock, () -> reentrantLock, () -> reentrantLock);
556         }
557     }
558 
559     /**
560      * Wraps a {@link StampedLock} and object to protect. Read methods use {@link StampedLock#asReadLock()}, and write methods use
561      * {@link StampedLock#asWriteLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
562      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
563      * holds the lock while the consumer or function is called.
564      *
565      * @param <O> The type of the object to protect.
566      * @see LockingVisitors#stampedLockVisitor(Object)
567      */
568     public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> {
569 
570         /**
571          * Builds {@link LockVisitor} instances.
572          *
573          * @param <O> The wrapped object type.
574          * @since 3.18.0
575          */
576         public static class Builder<O> extends LVBuilder<O, StampedLock, Builder<O>> {
577 
578             /**
579              * Constructs a new instance.
580              */
581             public Builder() {
582                 // empty
583             }
584 
585             @Override
586             public StampedLockVisitor<O> get() {
587                 return new StampedLockVisitor<>(this);
588             }
589 
590 
591             @Override
592             public Builder<O> setLock(final StampedLock stampedLock) {
593                 setReadLockSupplier(stampedLock::asReadLock);
594                 setWriteLockSupplier(stampedLock::asWriteLock);
595                 return super.setLock(stampedLock);
596             }
597         }
598 
599         /**
600          * Creates a new builder.
601          *
602          * @param <O> The wrapped object type.
603          * @return A new builder.
604          * @since 3.18.0
605          */
606         public static <O> Builder<O> builder() {
607             return new Builder<>();
608         }
609 
610         /**
611          * Constructs a new instance from a builder.
612          *
613          * @param builder A builder.
614          */
615         private StampedLockVisitor(final Builder<O> builder) {
616             super(builder);
617         }
618 
619         /**
620          * Creates a new instance with the given object and lock.
621          *
622          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
623          * @param stampedLock The lock to use.
624          * @see LockingVisitors
625          */
626         protected StampedLockVisitor(final O object, final StampedLock stampedLock) {
627             super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock);
628         }
629     }
630 
631     /**
632      * Creates a new instance of {@link ReadWriteLockVisitor} with the given object and lock.
633      *
634      * @param <O> The type of the object to protect.
635      * @param object The object to protect.
636      * @param readWriteLock The lock to use.
637      * @return A new {@link ReadWriteLockVisitor}.
638      * @see LockingVisitors
639      * @since 3.13.0
640      */
641     public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) {
642         return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock);
643     }
644 
645     /**
646      * Creates a new instance of {@link ReentrantLockVisitor} with the given object and lock.
647      *
648      * @param <O> The type of the object to protect.
649      * @param object The object to protect.
650      * @param reentrantLock The lock to use.
651      * @return A new {@link ReentrantLockVisitor}.
652      * @see LockingVisitors
653      * @since 3.18.0
654      */
655     public static <O> ReentrantLockVisitor<O> create(final O object, final ReentrantLock reentrantLock) {
656         return new LockingVisitors.ReentrantLockVisitor<>(object, reentrantLock);
657     }
658 
659     /**
660      * Creates a new instance of {@link ReentrantLockVisitor} with the given object.
661      *
662      * @param <O> The type of the object to protect.
663      * @param object The object to protect.
664      * @return A new {@link ReentrantLockVisitor}.
665      * @see LockingVisitors
666      * @since 3.18.0
667      */
668     public static <O> ReentrantLockVisitor<O> reentrantLockVisitor(final O object) {
669         return create(object, new ReentrantLock());
670     }
671 
672     /**
673      * Creates a new instance of {@link ReadWriteLockVisitor} with the given object.
674      *
675      * @param <O> The type of the object to protect.
676      * @param object The object to protect.
677      * @return A new {@link ReadWriteLockVisitor}.
678      * @see LockingVisitors
679      */
680     public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) {
681         return create(object, new ReentrantReadWriteLock());
682     }
683 
684     /**
685      * Creates a new instance of {@link StampedLockVisitor} with the given object.
686      *
687      * @param <O> The type of the object to protect.
688      * @param object The object to protect.
689      * @return A new {@link StampedLockVisitor}.
690      * @see LockingVisitors
691      */
692     public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) {
693         return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock());
694     }
695 
696     /**
697      * Make private in 4.0.
698      *
699      * @see LockingVisitors
700      * @deprecated TODO Make private in 4.0.
701      */
702     @Deprecated
703     public LockingVisitors() {
704         // empty
705     }
706 }