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 * The read and write methods use the locks supplied by the visitor. A {@link ReentrantLockVisitor} uses one exclusive lock for both methods.
37 * A {@link ReadWriteLockVisitor} uses the underlying read and write locks, while a {@link StampedLockVisitor} uses its read and write
38 * {@link Lock} views. Read operations may run concurrently only when the supplied lock supports shared reads.
39 * </p>
40 * <p>
41 * For example, to use this class with a {@link ReentrantLock}:
42 * </p>
43 * <ol>
44 * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a
45 * {@link LockingVisitors.ReentrantLockVisitor}
46 * </li>
47 * <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
48 * lock. Then call
49 * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or
50 * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.
51 * </li>
52 * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call
53 * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or
54 * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}.
55 * </li>
56 * </ol>
57 * <p>
58 * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}.
59 * </p>
60 *
61 * <pre>{@code
62 * public class SimpleLogger1 {
63 *
64 * private final ReentrantLockVisitor<PrintStream> lock;
65 * private final PrintStream ps;
66 *
67 * public SimpleLogger(OutputStream out) {
68 * ps = new PrintStream(out);
69 * lock = LockingVisitors.reentrantLockVisitor(ps);
70 * }
71 *
72 * public void log(String message) {
73 * lock.acceptWriteLocked(ps -> ps.println(message));
74 * }
75 *
76 * public void log(byte[] buffer) {
77 * lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
78 * }
79 * }
80 * }
81 * </pre>
82 *
83 * <p>
84 * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}.
85 * </p>
86 *
87 * <pre>{@code
88 * public class SimpleLogger2 {
89 *
90 * private final ReadWriteLockVisitor<PrintStream> lock;
91 * private final PrintStream ps;
92 *
93 * public SimpleLogger(OutputStream out) {
94 * ps = new PrintStream(out);
95 * lock = LockingVisitors.readWriteLockVisitor(ps);
96 * }
97 *
98 * public void log(String message) {
99 * 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 */
137 public 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 }