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 }