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 * The read and write methods use the locks supplied by the visitor. A {@link ReentrantLockVisitor} uses one exclusive lock for both methods. 037 * A {@link ReadWriteLockVisitor} uses the underlying read and write locks, while a {@link StampedLockVisitor} uses its read and write 038 * {@link Lock} views. Read operations may run concurrently only when the supplied lock supports shared reads. 039 * </p> 040 * <p> 041 * For example, to use this class with a {@link ReentrantLock}: 042 * </p> 043 * <ol> 044 * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a 045 * {@link LockingVisitors.ReentrantLockVisitor} 046 * </li> 047 * <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 048 * lock. Then call 049 * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or 050 * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer. 051 * </li> 052 * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call 053 * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or 054 * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}. 055 * </li> 056 * </ol> 057 * <p> 058 * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}. 059 * </p> 060 * 061 * <pre>{@code 062 * public class SimpleLogger1 { 063 * 064 * private final ReentrantLockVisitor<PrintStream> lock; 065 * private final PrintStream ps; 066 * 067 * public SimpleLogger(OutputStream out) { 068 * ps = new PrintStream(out); 069 * lock = LockingVisitors.reentrantLockVisitor(ps); 070 * } 071 * 072 * public void log(String message) { 073 * lock.acceptWriteLocked(ps -> ps.println(message)); 074 * } 075 * 076 * public void log(byte[] buffer) { 077 * lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); }); 078 * } 079 * } 080 * } 081 * </pre> 082 * 083 * <p> 084 * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}. 085 * </p> 086 * 087 * <pre>{@code 088 * public class SimpleLogger2 { 089 * 090 * private final ReadWriteLockVisitor<PrintStream> lock; 091 * private final PrintStream ps; 092 * 093 * public SimpleLogger(OutputStream out) { 094 * ps = new PrintStream(out); 095 * lock = LockingVisitors.readWriteLockVisitor(ps); 096 * } 097 * 098 * public void log(String message) { 099 * lock.acceptWriteLocked(ps -> ps.println(message)); 100 * } 101 * 102 * public void log(byte[] buffer) { 103 * lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); }); 104 * } 105 * } 106 * } 107 * </pre> 108 * 109 * <p> 110 * Example 3: A thread safe logger class using a {@link StampedLock}. 111 * </p> 112 * 113 * <pre>{@code 114 * public class SimpleLogger3 { 115 * 116 * private final StampedLockVisitor<PrintStream> lock; 117 * private final PrintStream ps; 118 * 119 * public SimpleLogger(OutputStream out) { 120 * ps = new PrintStream(out); 121 * lock = LockingVisitors.stampedLockVisitor(ps); 122 * } 123 * 124 * public void log(String message) { 125 * lock.acceptWriteLocked(ps -> ps.println(message)); 126 * } 127 * 128 * public void log(byte[] buffer) { 129 * lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); }); 130 * } 131 * } 132 * } 133 * </pre> 134 * 135 * @since 3.11 136 */ 137public class LockingVisitors { 138 139 /** 140 * Wraps a domain object and a lock for access by lambdas. 141 * 142 * @param <O> The wrapped object type. 143 * @param <L> The wrapped lock type. 144 * @see LockingVisitors 145 */ 146 public static class LockVisitor<O, L> { 147 148 /** 149 * Builds {@link LockVisitor} instances. 150 * 151 * @param <O> The wrapped object type. 152 * @param <L> The wrapped lock type. 153 * @param <B> The builder type. 154 * @since 3.18.0 155 */ 156 public static class LVBuilder<O, L, B extends LVBuilder<O, L, B>> extends AbstractSupplier<LockVisitor<O, L>, B, RuntimeException> { 157 158 /** 159 * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or 160 * {@link ReadWriteLock}. 161 */ 162 L lock; 163 164 /** 165 * The guarded object. 166 */ 167 O object; 168 169 /** 170 * Supplies the lock used by read methods. 171 */ 172 private Supplier<Lock> readLockSupplier; 173 174 /** 175 * Supplies the lock used by write methods. 176 */ 177 private Supplier<Lock> writeLockSupplier; 178 179 /** 180 * Constructs a new instance. 181 */ 182 public LVBuilder() { 183 // empty 184 } 185 186 @Override 187 public LockVisitor<O, L> get() { 188 return new LockVisitor<>(this); 189 } 190 191 Supplier<Lock> getReadLockSupplier() { 192 return readLockSupplier; 193 } 194 195 196 Supplier<Lock> getWriteLockSupplier() { 197 return writeLockSupplier; 198 } 199 200 /** 201 * Sets the underlying lock returned by {@link LockVisitor#getLock()}. 202 * 203 * @param lock The lock. 204 * @return {@code this} instance. 205 */ 206 public B setLock(final L lock) { 207 this.lock = lock; 208 return asThis(); 209 } 210 211 /** 212 * Sets the resource. 213 * 214 * @param object The resource. 215 * @return {@code this} instance. 216 */ 217 public B setObject(final O object) { 218 this.object = object; 219 return asThis(); 220 } 221 222 /** 223 * Sets the supplier of the lock used by read methods. 224 * 225 * @param readLockSupplier Supplies the read lock. 226 * @return {@code this} instance. 227 */ 228 public B setReadLockSupplier(final Supplier<Lock> readLockSupplier) { 229 this.readLockSupplier = readLockSupplier; 230 return asThis(); 231 } 232 233 /** 234 * Sets the supplier of the lock used by write methods. 235 * 236 * @param writeLockSupplier Supplies the write lock. 237 * @return {@code this} instance. 238 */ 239 public B setWriteLockSupplier(final Supplier<Lock> writeLockSupplier) { 240 this.writeLockSupplier = writeLockSupplier; 241 return asThis(); 242 } 243 } 244 245 /** 246 * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or 247 * {@link ReadWriteLock}. 248 */ 249 private final L lock; 250 251 /** 252 * The guarded object. 253 */ 254 private final O object; 255 256 /** 257 * Supplies the lock used by read methods. 258 */ 259 private final Supplier<Lock> readLockSupplier; 260 261 /** 262 * Supplies the lock used by write methods. 263 */ 264 private final Supplier<Lock> writeLockSupplier; 265 266 /** 267 * Constructs an instance from a builder. 268 * 269 * @param builder The builder. 270 */ 271 private LockVisitor(final LVBuilder<O, L, ?> builder) { 272 this.object = Objects.requireNonNull(builder.object, "object"); 273 this.lock = Objects.requireNonNull(builder.lock, "lock"); 274 this.readLockSupplier = Objects.requireNonNull(builder.readLockSupplier, "readLockSupplier"); 275 this.writeLockSupplier = Objects.requireNonNull(builder.writeLockSupplier, "writeLockSupplier"); 276 } 277 278 /** 279 * Constructs an instance. 280 * 281 * @param object The object to guard. 282 * @param lock The locking object. 283 * @param readLockSupplier Supplies the lock used by read methods. 284 * @param writeLockSupplier Supplies the lock used by write methods. 285 */ 286 protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) { 287 this.object = Objects.requireNonNull(object, "object"); 288 this.lock = Objects.requireNonNull(lock, "lock"); 289 this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier"); 290 this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier"); 291 } 292 293 /** 294 * Invokes the consumer while holding the lock supplied for read operations. 295 * The lock is released in a {@code finally} block after the consumer returns or throws. Whether other readers can proceed concurrently depends on the 296 * supplied lock. 297 * 298 * @param consumer The consumer of the guarded object. 299 * @see #acceptWriteLocked(FailableConsumer) 300 * @see #applyReadLocked(FailableFunction) 301 */ 302 public void acceptReadLocked(final FailableConsumer<O, ?> consumer) { 303 lockAcceptUnlock(readLockSupplier, consumer); 304 } 305 306 /** 307 * Invokes the consumer while holding the lock supplied for write operations. 308 * The lock is released in a {@code finally} block after the consumer returns or throws. 309 * 310 * @param consumer The consumer of the guarded object. 311 * @see #acceptReadLocked(FailableConsumer) 312 * @see #applyWriteLocked(FailableFunction) 313 */ 314 public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) { 315 lockAcceptUnlock(writeLockSupplier, consumer); 316 } 317 318 /** 319 * Applies the function while holding the lock supplied for read operations. 320 * The lock is released in a {@code finally} block after the function returns or throws. Whether other readers can proceed concurrently depends on the 321 * supplied lock. 322 * 323 * @param <T> The result type. 324 * @param function The function applied to the guarded object. 325 * @return The function result. 326 * @throws NullPointerException Thrown if the lock supplier is null or returns null. 327 * @see #acceptReadLocked(FailableConsumer) 328 * @see #applyWriteLocked(FailableFunction) 329 */ 330 public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) { 331 return lockApplyUnlock(readLockSupplier, function); 332 } 333 334 /** 335 * Applies the function while holding the lock supplied for write operations. 336 * The lock is released in a {@code finally} block after the function returns or throws. 337 * 338 * @param <T> The result type. 339 * @param function The function applied to the guarded object. 340 * @return The function result. 341 * @throws NullPointerException Thrown if the lock supplier is null or returns null. 342 * @see #acceptWriteLocked(FailableConsumer) 343 * @see #applyReadLocked(FailableFunction) 344 */ 345 public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) { 346 return lockApplyUnlock(writeLockSupplier, function); 347 } 348 349 /** 350 * Gets the lock. 351 * 352 * @return The lock. 353 */ 354 public L getLock() { 355 return lock; 356 } 357 358 /** 359 * Gets the guarded object. 360 * 361 * @return The object. 362 */ 363 public O getObject() { 364 return object; 365 } 366 367 /** 368 * Implements {@link #acceptReadLocked(FailableConsumer)} and 369 * {@link #acceptWriteLocked(FailableConsumer)}. 370 * 371 * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view. 372 * @param consumer The consumer of the guarded object. 373 * @see #acceptReadLocked(FailableConsumer) 374 * @see #acceptWriteLocked(FailableConsumer) 375 */ 376 protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) { 377 final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock"); 378 lock.lock(); 379 try { 380 Failable.accept(consumer, object); 381 } finally { 382 lock.unlock(); 383 } 384 } 385 386 /** 387 * Implements {@link #applyReadLocked(FailableFunction)} and 388 * {@link #applyWriteLocked(FailableFunction)}. 389 * 390 * @param <T> The result type. 391 * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view. 392 * @param function The function applied to the guarded object. 393 * @return The function result. 394 * @throws NullPointerException Thrown if the lock supplier is null or returns null. 395 * @see #applyReadLocked(FailableFunction) 396 * @see #applyWriteLocked(FailableFunction) 397 */ 398 protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) { 399 final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock"); 400 lock.lock(); 401 try { 402 return Failable.apply(function, object); 403 } finally { 404 lock.unlock(); 405 } 406 } 407 408 } 409 410 /** 411 * Wraps a {@link ReadWriteLock} and object to protect. Read methods use {@link ReadWriteLock#readLock()}, and write methods use 412 * {@link ReadWriteLock#writeLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)}, 413 * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor 414 * holds the lock while the consumer or function is called. 415 * 416 * @param <O> The type of the object to protect. 417 * @see LockingVisitors#create(Object, ReadWriteLock) 418 */ 419 public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> { 420 421 /** 422 * Builds {@link LockVisitor} instances. 423 * 424 * @param <O> The wrapped object type. 425 * @since 3.18.0 426 */ 427 public static class Builder<O> extends LVBuilder<O, ReadWriteLock, Builder<O>> { 428 429 /** 430 * Constructs a new instance. 431 */ 432 public Builder() { 433 // empty 434 } 435 436 @Override 437 public ReadWriteLockVisitor<O> get() { 438 return new ReadWriteLockVisitor<>(this); 439 } 440 441 @Override 442 public Builder<O> setLock(final ReadWriteLock readWriteLock) { 443 setReadLockSupplier(readWriteLock::readLock); 444 setWriteLockSupplier(readWriteLock::writeLock); 445 return super.setLock(readWriteLock); 446 } 447 } 448 449 /** 450 * Creates a new builder. 451 * 452 * @param <O> The wrapped object type. 453 * @return A new builder. 454 * @since 3.18.0 455 */ 456 public static <O> Builder<O> builder() { 457 return new Builder<>(); 458 } 459 460 /** 461 * Constructs a new instance from a builder. 462 * 463 * @param builder A builder. 464 */ 465 private ReadWriteLockVisitor(final Builder<O> builder) { 466 super(builder); 467 } 468 469 /** 470 * Creates a new instance with the given object and lock. 471 * 472 * @param object The object to protect. The caller is supposed to drop all references to the locked object. 473 * @param readWriteLock The lock to use. 474 * @see LockingVisitors 475 */ 476 protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) { 477 super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock); 478 } 479 480 } 481 482 /** 483 * Wraps a {@link ReentrantLock} and object to protect. Both read and write methods acquire the same exclusive lock. 484 * To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)}, 485 * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor 486 * holds the lock while the consumer or function is called. 487 * 488 * @param <O> The type of the object to protect. 489 * @see LockingVisitors#reentrantLockVisitor(Object) 490 * @since 3.18.0 491 */ 492 public static class ReentrantLockVisitor<O> extends LockVisitor<O, ReentrantLock> { 493 494 /** 495 * Builds {@link LockVisitor} instances. 496 * 497 * @param <O> The wrapped object type. 498 * @since 3.18.0 499 */ 500 public static class Builder<O> extends LVBuilder<O, ReentrantLock, Builder<O>> { 501 502 /** 503 * Constructs a new instance. 504 */ 505 public Builder() { 506 // empty 507 } 508 509 @Override 510 public ReentrantLockVisitor<O> get() { 511 return new ReentrantLockVisitor<>(this); 512 } 513 514 515 @Override 516 public Builder<O> setLock(final ReentrantLock reentrantLock) { 517 setReadLockSupplier(() -> reentrantLock); 518 setWriteLockSupplier(() -> reentrantLock); 519 return super.setLock(reentrantLock); 520 } 521 } 522 523 /** 524 * Creates a new builder. 525 * 526 * @param <O> The wrapped object type. 527 * @return A new builder. 528 * @since 3.18.0 529 */ 530 public static <O> Builder<O> builder() { 531 return new Builder<>(); 532 } 533 534 /** 535 * Constructs a new instance from a builder. 536 * 537 * @param builder A builder. 538 */ 539 private ReentrantLockVisitor(final Builder<O> builder) { 540 super(builder); 541 } 542 543 544 /** 545 * Creates a new instance with the given object and lock. 546 * <p> 547 * This visitor uses the given {@link ReentrantLock} for both read and write methods; both acquire it exclusively. 548 * </p> 549 * 550 * @param object The object to protect. The caller is supposed to drop all references to the locked object. 551 * @param reentrantLock The lock to use. 552 * @see LockingVisitors 553 */ 554 protected ReentrantLockVisitor(final O object, final ReentrantLock reentrantLock) { 555 super(object, reentrantLock, () -> reentrantLock, () -> reentrantLock); 556 } 557 } 558 559 /** 560 * Wraps a {@link StampedLock} and object to protect. Read methods use {@link StampedLock#asReadLock()}, and write methods use 561 * {@link StampedLock#asWriteLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)}, 562 * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor 563 * holds the lock while the consumer or function is called. 564 * 565 * @param <O> The type of the object to protect. 566 * @see LockingVisitors#stampedLockVisitor(Object) 567 */ 568 public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> { 569 570 /** 571 * Builds {@link LockVisitor} instances. 572 * 573 * @param <O> The wrapped object type. 574 * @since 3.18.0 575 */ 576 public static class Builder<O> extends LVBuilder<O, StampedLock, Builder<O>> { 577 578 /** 579 * Constructs a new instance. 580 */ 581 public Builder() { 582 // empty 583 } 584 585 @Override 586 public StampedLockVisitor<O> get() { 587 return new StampedLockVisitor<>(this); 588 } 589 590 591 @Override 592 public Builder<O> setLock(final StampedLock stampedLock) { 593 setReadLockSupplier(stampedLock::asReadLock); 594 setWriteLockSupplier(stampedLock::asWriteLock); 595 return super.setLock(stampedLock); 596 } 597 } 598 599 /** 600 * Creates a new builder. 601 * 602 * @param <O> The wrapped object type. 603 * @return A new builder. 604 * @since 3.18.0 605 */ 606 public static <O> Builder<O> builder() { 607 return new Builder<>(); 608 } 609 610 /** 611 * Constructs a new instance from a builder. 612 * 613 * @param builder A builder. 614 */ 615 private StampedLockVisitor(final Builder<O> builder) { 616 super(builder); 617 } 618 619 /** 620 * Creates a new instance with the given object and lock. 621 * 622 * @param object The object to protect. The caller is supposed to drop all references to the locked object. 623 * @param stampedLock The lock to use. 624 * @see LockingVisitors 625 */ 626 protected StampedLockVisitor(final O object, final StampedLock stampedLock) { 627 super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock); 628 } 629 } 630 631 /** 632 * Creates a new instance of {@link ReadWriteLockVisitor} with the given object and lock. 633 * 634 * @param <O> The type of the object to protect. 635 * @param object The object to protect. 636 * @param readWriteLock The lock to use. 637 * @return A new {@link ReadWriteLockVisitor}. 638 * @see LockingVisitors 639 * @since 3.13.0 640 */ 641 public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) { 642 return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock); 643 } 644 645 /** 646 * Creates a new instance of {@link ReentrantLockVisitor} with the given object and lock. 647 * 648 * @param <O> The type of the object to protect. 649 * @param object The object to protect. 650 * @param reentrantLock The lock to use. 651 * @return A new {@link ReentrantLockVisitor}. 652 * @see LockingVisitors 653 * @since 3.18.0 654 */ 655 public static <O> ReentrantLockVisitor<O> create(final O object, final ReentrantLock reentrantLock) { 656 return new LockingVisitors.ReentrantLockVisitor<>(object, reentrantLock); 657 } 658 659 /** 660 * Creates a new instance of {@link ReentrantLockVisitor} with the given object. 661 * 662 * @param <O> The type of the object to protect. 663 * @param object The object to protect. 664 * @return A new {@link ReentrantLockVisitor}. 665 * @see LockingVisitors 666 * @since 3.18.0 667 */ 668 public static <O> ReentrantLockVisitor<O> reentrantLockVisitor(final O object) { 669 return create(object, new ReentrantLock()); 670 } 671 672 /** 673 * Creates a new instance of {@link ReadWriteLockVisitor} with the given object. 674 * 675 * @param <O> The type of the object to protect. 676 * @param object The object to protect. 677 * @return A new {@link ReadWriteLockVisitor}. 678 * @see LockingVisitors 679 */ 680 public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) { 681 return create(object, new ReentrantReadWriteLock()); 682 } 683 684 /** 685 * Creates a new instance of {@link StampedLockVisitor} with the given object. 686 * 687 * @param <O> The type of the object to protect. 688 * @param object The object to protect. 689 * @return A new {@link StampedLockVisitor}. 690 * @see LockingVisitors 691 */ 692 public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) { 693 return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock()); 694 } 695 696 /** 697 * Make private in 4.0. 698 * 699 * @see LockingVisitors 700 * @deprecated TODO Make private in 4.0. 701 */ 702 @Deprecated 703 public LockingVisitors() { 704 // empty 705 } 706}