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}