Source code
Description: source: package: org.apache.commons.lang3.concurrent.locks, class: LockingVisitors, class: ReadWriteLockVisitor

    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}