001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.concurrent.locks;
018
019import java.util.Objects;
020import java.util.concurrent.locks.Lock;
021import java.util.concurrent.locks.ReadWriteLock;
022import java.util.concurrent.locks.ReentrantLock;
023import java.util.concurrent.locks.ReentrantReadWriteLock;
024import java.util.concurrent.locks.StampedLock;
025import java.util.function.Supplier;
026
027import org.apache.commons.lang3.builder.AbstractSupplier;
028import org.apache.commons.lang3.function.Failable;
029import org.apache.commons.lang3.function.FailableConsumer;
030import org.apache.commons.lang3.function.FailableFunction;
031import org.apache.commons.lang3.function.Suppliers;
032
033/**
034 * Combines the monitor and visitor pattern to work with {@link Lock}s as an alternative to synchronization.
035 * <p>
036 * Locking may be preferable to synchronization or when an application needs a distinction between read access (multiple threads may have read access
037 * concurrently) and write access (only one thread may have write access at any given time).
038 * </p>
039 * <p>
040 * For example, to use this class with a {@link ReentrantLock}:
041 * </p>
042 * <ol>
043 * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a
044 * {@link LockingVisitors.ReentrantLockVisitor}
045 * </li>
046 * <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
047 * lock. Then call
048 * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or
049 * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.
050 * </li>
051 * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call
052 * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or
053 * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}.
054 * </li>
055 * </ol>
056 * <p>
057 * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}.
058 * </p>
059 *
060 * <pre>{@code
061 *   public class SimpleLogger1 {
062 *
063 *     private final ReentrantLockVisitor<PrintStream> lock;
064 *     private final PrintStream ps;
065 *
066 *     public SimpleLogger(OutputStream out) {
067 *         ps = new PrintStream(out);
068 *         lock = LockingVisitors.reentrantLockVisitor(ps);
069 *     }
070 *
071 *     public void log(String message) {
072 *         lock.acceptWriteLocked(ps -> ps.println(message));
073 *     }
074 *
075 *     public void log(byte[] buffer) {
076 *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
077 *     }
078 * }
079 * }
080 * </pre>
081 *
082 * <p>
083 * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}.
084 * </p>
085 *
086 * <pre>{@code
087 *   public class SimpleLogger2 {
088 *
089 *     private final ReadWriteLockVisitor<PrintStream> lock;
090 *     private final PrintStream ps;
091 *
092 *     public SimpleLogger(OutputStream out) {
093 *         ps = new PrintStream(out);
094 *         lock = LockingVisitors.readWriteLockVisitor(ps);
095 *     }
096 *
097 *     public void log(String message) {
098 *         lock.acceptWriteLocked(ps -> ps.println(message));
099 *     }
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 */
136public 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}