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   * Locking may be preferable to synchronization or when an application needs a distinction between read access (multiple threads may have read access
37   * concurrently) and write access (only one thread may have write access at any given time).
38   * </p>
39   * <p>
40   * For example, to use this class with a {@link ReentrantLock}:
41   * </p>
42   * <ol>
43   * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a
44   * {@link LockingVisitors.ReentrantLockVisitor}
45   * </li>
46   * <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
47   * lock. Then call
48   * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or
49   * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.
50   * </li>
51   * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call
52   * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or
53   * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}.
54   * </li>
55   * </ol>
56   * <p>
57   * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}.
58   * </p>
59   *
60   * <pre>{@code
61   *   public class SimpleLogger1 {
62   *
63   *     private final ReentrantLockVisitor<PrintStream> lock;
64   *     private final PrintStream ps;
65   *
66   *     public SimpleLogger(OutputStream out) {
67   *         ps = new PrintStream(out);
68   *         lock = LockingVisitors.reentrantLockVisitor(ps);
69   *     }
70   *
71   *     public void log(String message) {
72   *         lock.acceptWriteLocked(ps -> ps.println(message));
73   *     }
74   *
75   *     public void log(byte[] buffer) {
76   *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
77   *     }
78   * }
79   * }
80   * </pre>
81   *
82   * <p>
83   * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}.
84   * </p>
85   *
86   * <pre>{@code
87   *   public class SimpleLogger2 {
88   *
89   *     private final ReadWriteLockVisitor<PrintStream> lock;
90   *     private final PrintStream ps;
91   *
92   *     public SimpleLogger(OutputStream out) {
93   *         ps = new PrintStream(out);
94   *         lock = LockingVisitors.readWriteLockVisitor(ps);
95   *     }
96   *
97   *     public void log(String message) {
98   *         lock.acceptWriteLocked(ps -> ps.println(message));
99   *     }
100  *
101  *     public void log(byte[] buffer) {
102  *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
103  *     }
104  * }
105  * }
106  * </pre>
107  *
108  * <p>
109  * Example 3: A thread safe logger class using a {@link StampedLock}.
110  * </p>
111  *
112  * <pre>{@code
113  *   public class SimpleLogger3 {
114  *
115  *     private final StampedLockVisitor<PrintStream> lock;
116  *     private final PrintStream ps;
117  *
118  *     public SimpleLogger(OutputStream out) {
119  *         ps = new PrintStream(out);
120  *         lock = LockingVisitors.stampedLockVisitor(ps);
121  *     }
122  *
123  *     public void log(String message) {
124  *         lock.acceptWriteLocked(ps -> ps.println(message));
125  *     }
126  *
127  *     public void log(byte[] buffer) {
128  *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
129  *     }
130  * }
131  * }
132  * </pre>
133  *
134  * @since 3.11
135  */
136 public class LockingVisitors {
137 
138     /**
139      * Wraps a domain object and a lock for access by lambdas.
140      *
141      * @param <O> the wrapped object type.
142      * @param <L> the wrapped lock type.
143      * @see LockingVisitors
144      */
145     public static class LockVisitor<O, L> {
146 
147         /**
148          * Builds {@link LockVisitor} instances.
149          *
150          * @param <O> the wrapped object type.
151          * @param <L> the wrapped lock type.
152          * @param <B> the builder type.
153          * @since 3.18.0
154          */
155         public static class LVBuilder<O, L, B extends LVBuilder<O, L, B>> extends AbstractSupplier<LockVisitor<O, L>, B, RuntimeException> {
156 
157             /**
158              * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
159              * Java 8.
160              */
161             L lock;
162 
163             /**
164              * The guarded object.
165              */
166             O object;
167 
168             /**
169              * Supplies the read lock, usually from the lock object.
170              */
171             private Supplier<Lock> readLockSupplier;
172 
173             /**
174              * Supplies the write lock, usually from the lock object.
175              */
176             private Supplier<Lock> writeLockSupplier;
177 
178             /**
179              * Constructs a new instance.
180              */
181             public LVBuilder() {
182                 // empty
183             }
184 
185             @Override
186             public LockVisitor<O, L> get() {
187                 return new LockVisitor<>(this);
188             }
189 
190             Supplier<Lock> getReadLockSupplier() {
191                 return readLockSupplier;
192             }
193 
194 
195             Supplier<Lock> getWriteLockSupplier() {
196                 return writeLockSupplier;
197             }
198 
199             /**
200              * Set the lock used from accept methods.
201              *
202              * @param lock the lock.
203              * @return {@code this} instance.
204              */
205             public B setLock(final L lock) {
206                 this.lock = lock;
207                 return asThis();
208             }
209 
210             /**
211              * Set the resource.
212              *
213              * @param object the resource.
214              * @return {@code this} instance.
215              */
216             public B setObject(final O object) {
217                 this.object = object;
218                 return asThis();
219             }
220 
221             /**
222              * Supplies the read lock.
223              *
224              * @param readLockSupplier Supplies the read lock.
225              * @return {@code this} instance.
226              */
227             public B setReadLockSupplier(final Supplier<Lock> readLockSupplier) {
228                 this.readLockSupplier = readLockSupplier;
229                 return asThis();
230             }
231 
232             /**
233              * Supplies the write lock.
234              *
235              * @param writeLockSupplier Supplies the write lock.
236              * @return {@code this} instance.
237              */
238             public B setWriteLockSupplier(final Supplier<Lock> writeLockSupplier) {
239                 this.writeLockSupplier = writeLockSupplier;
240                 return asThis();
241             }
242         }
243 
244         /**
245          * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
246          * Java 8.
247          */
248         private final L lock;
249 
250         /**
251          * The guarded object.
252          */
253         private final O object;
254 
255         /**
256          * Supplies the read lock, usually from the lock object.
257          */
258         private final Supplier<Lock> readLockSupplier;
259 
260         /**
261          * Supplies the write lock, usually from the lock object.
262          */
263         private final Supplier<Lock> writeLockSupplier;
264 
265         /**
266          * Constructs an instance from a builder.
267          *
268          * @param builder The builder.
269          */
270         private LockVisitor(final LVBuilder<O, L, ?> builder) {
271             this.object = Objects.requireNonNull(builder.object, "object");
272             this.lock = Objects.requireNonNull(builder.lock, "lock");
273             this.readLockSupplier = Objects.requireNonNull(builder.readLockSupplier, "readLockSupplier");
274             this.writeLockSupplier = Objects.requireNonNull(builder.writeLockSupplier, "writeLockSupplier");
275         }
276 
277         /**
278          * Constructs an instance.
279          *
280          * @param object The object to guard.
281          * @param lock The locking object.
282          * @param readLockSupplier Supplies the read lock, usually from the lock object.
283          * @param writeLockSupplier Supplies the write lock, usually from the lock object.
284          */
285         protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) {
286             this.object = Objects.requireNonNull(object, "object");
287             this.lock = Objects.requireNonNull(lock, "lock");
288             this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier");
289             this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier");
290         }
291 
292         /**
293          * Provides read (shared, non-exclusive) access to The object to protect. More precisely, what the method
294          * will do (in the given order):
295          *
296          * <ol>
297          * <li>Obtain a read (shared) lock on The object to protect. The current thread may block, until such a
298          * lock is granted.</li>
299          * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
300          * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
301          * lock will be released anyways.</li>
302          * </ol>
303          *
304          * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
305          *        consumers parameter.
306          * @see #acceptWriteLocked(FailableConsumer)
307          * @see #applyReadLocked(FailableFunction)
308          */
309         public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
310             lockAcceptUnlock(readLockSupplier, consumer);
311         }
312 
313         /**
314          * Provides write (exclusive) access to The object to protect. More precisely, what the method will do (in
315          * the given order):
316          *
317          * <ol>
318          * <li>Obtain a write (shared) lock on The object to protect. The current thread may block, until such a
319          * lock is granted.</li>
320          * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
321          * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
322          * lock will be released anyways.</li>
323          * </ol>
324          *
325          * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
326          *        consumers parameter.
327          * @see #acceptReadLocked(FailableConsumer)
328          * @see #applyWriteLocked(FailableFunction)
329          */
330         public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
331             lockAcceptUnlock(writeLockSupplier, consumer);
332         }
333 
334         /**
335          * Provides read (shared, non-exclusive) access to The object to protect for the purpose of computing a
336          * result object. More precisely, what the method will do (in the given order):
337          *
338          * <ol>
339          * <li>Obtain a read (shared) lock on The object to protect. The current thread may block, until such a
340          * lock is granted.</li>
341          * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
342          * receiving the functions result.</li>
343          * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
344          * lock will be released anyways.</li>
345          * <li>Return the result object, that has been received from the functions invocation.</li>
346          * </ol>
347          * <p>
348          * <em>Example:</em> Consider that the hidden object is a list, and we wish to know the current size of the
349          * list. This might be achieved with the following:
350          * </p>
351          * <pre>{@code
352          * private Lock<List<Object>> listLock;
353          *
354          * public int getCurrentListSize() {
355          *     final Integer sizeInteger = listLock.applyReadLocked(list -> Integer.valueOf(list.size));
356          *     return sizeInteger.intValue();
357          * }
358          * }
359          * </pre>
360          *
361          * @param <T> The result type (both the functions, and this method's.)
362          * @param function The function, which is being invoked to compute the result. The function will receive the
363          *        hidden object.
364          * @return The result object, which has been returned by the functions invocation.
365          * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
366          *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
367          * @see #acceptReadLocked(FailableConsumer)
368          * @see #applyWriteLocked(FailableFunction)
369          */
370         public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
371             return lockApplyUnlock(readLockSupplier, function);
372         }
373 
374         /**
375          * Provides write (exclusive) access to The object to protect for the purpose of computing a result object.
376          * More precisely, what the method will do (in the given order):
377          *
378          * <ol>
379          * <li>Obtain a read (shared) lock on The object to protect. The current thread may block, until such a
380          * lock is granted.</li>
381          * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
382          * receiving the functions result.</li>
383          * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
384          * lock will be released anyways.</li>
385          * <li>Return the result object, that has been received from the functions invocation.</li>
386          * </ol>
387          *
388          * @param <T> The result type (both the functions, and this method's.)
389          * @param function The function, which is being invoked to compute the result. The function will receive the
390          *        hidden object.
391          * @return The result object, which has been returned by the functions invocation.
392          * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
393          *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
394          * @see #acceptReadLocked(FailableConsumer)
395          * @see #applyWriteLocked(FailableFunction)
396          */
397         public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
398             return lockApplyUnlock(writeLockSupplier, function);
399         }
400 
401         /**
402          * Gets the lock.
403          *
404          * @return the lock.
405          */
406         public L getLock() {
407             return lock;
408         }
409 
410         /**
411          * Gets the guarded object.
412          *
413          * @return the object.
414          */
415         public O getObject() {
416             return object;
417         }
418 
419         /**
420          * This method provides the default implementation for {@link #acceptReadLocked(FailableConsumer)}, and
421          * {@link #acceptWriteLocked(FailableConsumer)}.
422          *
423          * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
424          *        internally.)
425          * @param consumer The consumer, which is to be given access to The object to protect, which will be passed
426          *        as a parameter.
427          * @see #acceptReadLocked(FailableConsumer)
428          * @see #acceptWriteLocked(FailableConsumer)
429          */
430         protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) {
431             final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
432             lock.lock();
433             try {
434                 Failable.accept(consumer, object);
435             } finally {
436                 lock.unlock();
437             }
438         }
439 
440         /**
441          * This method provides the actual implementation for {@link #applyReadLocked(FailableFunction)}, and
442          * {@link #applyWriteLocked(FailableFunction)}.
443          *
444          * @param <T> The result type (both the functions, and this method's.)
445          * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
446          *        internally.)
447          * @param function The function, which is being invoked to compute the result object. This function will receive
448          *        The object to protect as a parameter.
449          * @return The result object, which has been returned by the functions invocation.
450          * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
451          *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
452          * @see #applyReadLocked(FailableFunction)
453          * @see #applyWriteLocked(FailableFunction)
454          */
455         protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) {
456             final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
457             lock.lock();
458             try {
459                 return Failable.apply(function, object);
460             } finally {
461                 lock.unlock();
462             }
463         }
464 
465     }
466 
467     /**
468      * Wraps a {@link ReadWriteLock} and object to protect. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
469      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
470      * holds the lock while the consumer or function is called.
471      *
472      * @param <O> The type of the object to protect.
473      * @see LockingVisitors#create(Object, ReadWriteLock)
474      */
475     public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> {
476 
477         /**
478          * Builds {@link LockVisitor} instances.
479          *
480          * @param <O> the wrapped object type.
481          * @since 3.18.0
482          */
483         public static class Builder<O> extends LVBuilder<O, ReadWriteLock, Builder<O>> {
484 
485             /**
486              * Constructs a new instance.
487              */
488             public Builder() {
489                 // empty
490             }
491 
492             @Override
493             public ReadWriteLockVisitor<O> get() {
494                 return new ReadWriteLockVisitor<>(this);
495             }
496 
497             @Override
498             public Builder<O> setLock(final ReadWriteLock readWriteLock) {
499                 setReadLockSupplier(readWriteLock::readLock);
500                 setWriteLockSupplier(readWriteLock::writeLock);
501                 return super.setLock(readWriteLock);
502             }
503         }
504 
505         /**
506          * Creates a new builder.
507          *
508          * @param <O> the wrapped object type.
509          * @return a new builder.
510          * @since 3.18.0
511          */
512         public static <O> Builder<O> builder() {
513             return new Builder<>();
514         }
515 
516         /**
517          * Constructs a new instance from a builder.
518          *
519          * @param builder a builder.
520          */
521         private ReadWriteLockVisitor(final Builder<O> builder) {
522             super(builder);
523         }
524 
525         /**
526          * Creates a new instance with the given object and lock.
527          *
528          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
529          * @param readWriteLock the lock to use.
530          * @see LockingVisitors
531          */
532         protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) {
533             super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock);
534         }
535 
536     }
537 
538     /**
539      * Wraps a {@link ReentrantLock} and object to protect. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
540      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
541      * holds the lock while the consumer or function is called.
542      *
543      * @param <O> The type of the object to protect.
544      * @see LockingVisitors#reentrantLockVisitor(Object)
545      * @since 3.18.0
546      */
547     public static class ReentrantLockVisitor<O> extends LockVisitor<O, ReentrantLock> {
548 
549         /**
550          * Builds {@link LockVisitor} instances.
551          *
552          * @param <O> the wrapped object type.
553          * @since 3.18.0
554          */
555         public static class Builder<O> extends LVBuilder<O, ReentrantLock, Builder<O>> {
556 
557             /**
558              * Constructs a new instance.
559              */
560             public Builder() {
561                 // empty
562             }
563 
564             @Override
565             public ReentrantLockVisitor<O> get() {
566                 return new ReentrantLockVisitor<>(this);
567             }
568 
569 
570             @Override
571             public Builder<O> setLock(final ReentrantLock reentrantLock) {
572                 setReadLockSupplier(() -> reentrantLock);
573                 setWriteLockSupplier(() -> reentrantLock);
574                 return super.setLock(reentrantLock);
575             }
576         }
577 
578         /**
579          * Creates a new builder.
580          *
581          * @param <O> the wrapped object type.
582          * @return a new builder.
583          * @since 3.18.0
584          */
585         public static <O> Builder<O> builder() {
586             return new Builder<>();
587         }
588 
589         /**
590          * Constructs a new instance from a builder.
591          *
592          * @param builder a builder.
593          */
594         private ReentrantLockVisitor(final Builder<O> builder) {
595             super(builder);
596         }
597 
598 
599         /**
600          * Creates a new instance with the given object and lock.
601          * <p>
602          * This visitor uses the given ReentrantLock for all of its accept and apply methods.
603          * </p>
604          *
605          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
606          * @param reentrantLock the lock to use.
607          * @see LockingVisitors
608          */
609         protected ReentrantLockVisitor(final O object, final ReentrantLock reentrantLock) {
610             super(object, reentrantLock, () -> reentrantLock, () -> reentrantLock);
611         }
612     }
613 
614     /**
615      * Wraps a {@link StampedLock} and object to protect. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
616      * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
617      * holds the lock while the consumer or function is called.
618      *
619      * @param <O> The type of the object to protect.
620      * @see LockingVisitors#stampedLockVisitor(Object)
621      */
622     public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> {
623 
624         /**
625          * Builds {@link LockVisitor} instances.
626          *
627          * @param <O> the wrapped object type.
628          * @since 3.18.0
629          */
630         public static class Builder<O> extends LVBuilder<O, StampedLock, Builder<O>> {
631 
632             /**
633              * Constructs a new instance.
634              */
635             public Builder() {
636                 // empty
637             }
638 
639             @Override
640             public StampedLockVisitor<O> get() {
641                 return new StampedLockVisitor<>(this);
642             }
643 
644 
645             @Override
646             public Builder<O> setLock(final StampedLock stampedLock) {
647                 setReadLockSupplier(stampedLock::asReadLock);
648                 setWriteLockSupplier(stampedLock::asWriteLock);
649                 return super.setLock(stampedLock);
650             }
651         }
652 
653         /**
654          * Creates a new builder.
655          *
656          * @param <O> the wrapped object type.
657          * @return a new builder.
658          * @since 3.18.0
659          */
660         public static <O> Builder<O> builder() {
661             return new Builder<>();
662         }
663 
664         /**
665          * Constructs a new instance from a builder.
666          *
667          * @param builder a builder.
668          */
669         private StampedLockVisitor(final Builder<O> builder) {
670             super(builder);
671         }
672 
673         /**
674          * Creates a new instance with the given object and lock.
675          *
676          * @param object The object to protect. The caller is supposed to drop all references to the locked object.
677          * @param stampedLock the lock to use.
678          * @see LockingVisitors
679          */
680         protected StampedLockVisitor(final O object, final StampedLock stampedLock) {
681             super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock);
682         }
683     }
684 
685     /**
686      * Creates a new instance of {@link ReadWriteLockVisitor} with the given object and lock.
687      *
688      * @param <O> The type of the object to protect.
689      * @param object The object to protect.
690      * @param readWriteLock The lock to use.
691      * @return A new {@link ReadWriteLockVisitor}.
692      * @see LockingVisitors
693      * @since 3.13.0
694      */
695     public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) {
696         return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock);
697     }
698 
699     /**
700      * Creates a new instance of {@link ReentrantLockVisitor} with the given object and lock.
701      *
702      * @param <O> The type of the object to protect.
703      * @param object The object to protect.
704      * @param reentrantLock The lock to use.
705      * @return A new {@link ReentrantLockVisitor}.
706      * @see LockingVisitors
707      * @since 3.18.0
708      */
709     public static <O> ReentrantLockVisitor<O> create(final O object, final ReentrantLock reentrantLock) {
710         return new LockingVisitors.ReentrantLockVisitor<>(object, reentrantLock);
711     }
712 
713     /**
714      * Creates a new instance of {@link ReentrantLockVisitor} with the given object.
715      *
716      * @param <O> The type of the object to protect.
717      * @param object The object to protect.
718      * @return A new {@link ReentrantLockVisitor}.
719      * @see LockingVisitors
720      * @since 3.18.0
721      */
722     public static <O> ReentrantLockVisitor<O> reentrantLockVisitor(final O object) {
723         return create(object, new ReentrantLock());
724     }
725 
726     /**
727      * Creates a new instance of {@link ReadWriteLockVisitor} with the given object.
728      *
729      * @param <O> The type of the object to protect.
730      * @param object The object to protect.
731      * @return A new {@link ReadWriteLockVisitor}.
732      * @see LockingVisitors
733      */
734     public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) {
735         return create(object, new ReentrantReadWriteLock());
736     }
737 
738     /**
739      * Creates a new instance of {@link StampedLockVisitor} with the given object.
740      *
741      * @param <O> The type of the object to protect.
742      * @param object The object to protect.
743      * @return A new {@link StampedLockVisitor}.
744      * @see LockingVisitors
745      */
746     public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) {
747         return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock());
748     }
749 
750     /**
751      * Make private in 4.0.
752      *
753      * @see LockingVisitors
754      * @deprecated TODO Make private in 4.0.
755      */
756     @Deprecated
757     public LockingVisitors() {
758         // empty
759     }
760 }