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 * http://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.ReentrantReadWriteLock; 023import java.util.concurrent.locks.StampedLock; 024import java.util.function.Supplier; 025 026import org.apache.commons.lang3.function.Failable; 027import org.apache.commons.lang3.function.FailableConsumer; 028import org.apache.commons.lang3.function.FailableFunction; 029import org.apache.commons.lang3.function.Suppliers; 030 031/** 032 * Combines the monitor and visitor pattern to work with {@link java.util.concurrent.locks.Lock locked objects}. Locked 033 * objects are an alternative to synchronization. This, on Wikipedia, is known as the Visitor pattern 034 * (https://en.wikipedia.org/wiki/Visitor_pattern), and from the "Gang of Four" "Design Patterns" book's Visitor pattern 035 * [Gamma, E., Helm, R., & Johnson, R. (1998). Visitor. In Design patterns elements of reusable object oriented software (pp. 331-344). Reading: Addison Wesley.]. 036 * 037 * <p> 038 * Locking is preferable, if there is a distinction between read access (multiple threads may have read access 039 * concurrently), and write access (only one thread may have write access at any given time). In comparison, 040 * synchronization doesn't support read access, because synchronized access is exclusive. 041 * </p> 042 * <p> 043 * Using this class is fairly straightforward: 044 * </p> 045 * <ol> 046 * <li>While still in single thread mode, create an instance of {@link LockingVisitors.StampedLockVisitor} by calling 047 * {@link #stampedLockVisitor(Object)}, passing the object which needs to be locked. Discard all references to the 048 * locked object. Instead, use references to the lock.</li> 049 * <li>If you want to access the locked object, create a {@link FailableConsumer}. The consumer will receive the locked 050 * object as a parameter. For convenience, the consumer may be implemented as a Lambda. Then invoke 051 * {@link LockingVisitors.StampedLockVisitor#acceptReadLocked(FailableConsumer)}, or 052 * {@link LockingVisitors.StampedLockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.</li> 053 * <li>As an alternative, if you need to produce a result object, you may use a {@link FailableFunction}. This function 054 * may also be implemented as a Lambda. To have the function executed, invoke 055 * {@link LockingVisitors.StampedLockVisitor#applyReadLocked(FailableFunction)}, or 056 * {@link LockingVisitors.StampedLockVisitor#applyWriteLocked(FailableFunction)}.</li> 057 * </ol> 058 * <p> 059 * Example: A thread safe logger class. 060 * </p> 061 * 062 * <pre>{@code 063 * public class SimpleLogger { 064 * 065 * private final StampedLockVisitor<PrintStream> lock; 066 * 067 * public SimpleLogger(OutputStream out) { 068 * lock = LockingVisitors.stampedLockVisitor(new PrintStream(out)); 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 * @since 3.11 083 */ 084public class LockingVisitors { 085 086 /** 087 * Wraps a domain object and a lock for access by lambdas. 088 * 089 * @param <O> the wrapped object type. 090 * @param <L> the wrapped lock type. 091 */ 092 public static class LockVisitor<O, L> { 093 094 /** 095 * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in 096 * Java 8. 097 */ 098 private final L lock; 099 100 /** 101 * The guarded object. 102 */ 103 private final O object; 104 105 /** 106 * Supplies the read lock, usually from the lock object. 107 */ 108 private final Supplier<Lock> readLockSupplier; 109 110 /** 111 * Supplies the write lock, usually from the lock object. 112 */ 113 private final Supplier<Lock> writeLockSupplier; 114 115 /** 116 * Constructs an instance. 117 * 118 * @param object The object to guard. 119 * @param lock The locking object. 120 * @param readLockSupplier Supplies the read lock, usually from the lock object. 121 * @param writeLockSupplier Supplies the write lock, usually from the lock object. 122 */ 123 protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) { 124 this.object = Objects.requireNonNull(object, "object"); 125 this.lock = Objects.requireNonNull(lock, "lock"); 126 this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier"); 127 this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier"); 128 } 129 130 /** 131 * Provides read (shared, non-exclusive) access to the locked (hidden) object. More precisely, what the method 132 * will do (in the given order): 133 * 134 * <ol> 135 * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a 136 * lock is granted.</li> 137 * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li> 138 * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the 139 * lock will be released anyways.</li> 140 * </ol> 141 * 142 * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the 143 * consumers parameter. 144 * @see #acceptWriteLocked(FailableConsumer) 145 * @see #applyReadLocked(FailableFunction) 146 */ 147 public void acceptReadLocked(final FailableConsumer<O, ?> consumer) { 148 lockAcceptUnlock(readLockSupplier, consumer); 149 } 150 151 /** 152 * Provides write (exclusive) access to the locked (hidden) object. More precisely, what the method will do (in 153 * the given order): 154 * 155 * <ol> 156 * <li>Obtain a write (shared) lock on the locked (hidden) object. The current thread may block, until such a 157 * lock is granted.</li> 158 * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li> 159 * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the 160 * lock will be released anyways.</li> 161 * </ol> 162 * 163 * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the 164 * consumers parameter. 165 * @see #acceptReadLocked(FailableConsumer) 166 * @see #applyWriteLocked(FailableFunction) 167 */ 168 public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) { 169 lockAcceptUnlock(writeLockSupplier, consumer); 170 } 171 172 /** 173 * Provides read (shared, non-exclusive) access to the locked (hidden) object for the purpose of computing a 174 * result object. More precisely, what the method will do (in the given order): 175 * 176 * <ol> 177 * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a 178 * lock is granted.</li> 179 * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter, 180 * receiving the functions result.</li> 181 * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the 182 * lock will be released anyways.</li> 183 * <li>Return the result object, that has been received from the functions invocation.</li> 184 * </ol> 185 * <p> 186 * <em>Example:</em> Consider that the hidden object is a list, and we wish to know the current size of the 187 * list. This might be achieved with the following: 188 * </p> 189 * <pre>{@code 190 * private Lock<List<Object>> listLock; 191 * 192 * public int getCurrentListSize() { 193 * final Integer sizeInteger = listLock.applyReadLocked(list -> Integer.valueOf(list.size)); 194 * return sizeInteger.intValue(); 195 * } 196 * } 197 * </pre> 198 * 199 * @param <T> The result type (both the functions, and this method's.) 200 * @param function The function, which is being invoked to compute the result. The function will receive the 201 * hidden object. 202 * @return The result object, which has been returned by the functions invocation. 203 * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend 204 * access to the hidden object beyond this methods lifetime and will therefore be prevented. 205 * @see #acceptReadLocked(FailableConsumer) 206 * @see #applyWriteLocked(FailableFunction) 207 */ 208 public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) { 209 return lockApplyUnlock(readLockSupplier, function); 210 } 211 212 /** 213 * Provides write (exclusive) access to the locked (hidden) object for the purpose of computing a result object. 214 * More precisely, what the method will do (in the given order): 215 * 216 * <ol> 217 * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a 218 * lock is granted.</li> 219 * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter, 220 * receiving the functions result.</li> 221 * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the 222 * lock will be released anyways.</li> 223 * <li>Return the result object, that has been received from the functions invocation.</li> 224 * </ol> 225 * 226 * @param <T> The result type (both the functions, and this method's.) 227 * @param function The function, which is being invoked to compute the result. The function will receive the 228 * hidden object. 229 * @return The result object, which has been returned by the functions invocation. 230 * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend 231 * access to the hidden object beyond this methods lifetime and will therefore be prevented. 232 * @see #acceptReadLocked(FailableConsumer) 233 * @see #applyWriteLocked(FailableFunction) 234 */ 235 public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) { 236 return lockApplyUnlock(writeLockSupplier, function); 237 } 238 239 /** 240 * Gets the lock. 241 * 242 * @return the lock. 243 */ 244 public L getLock() { 245 return lock; 246 } 247 248 /** 249 * Gets the guarded object. 250 * 251 * @return the object. 252 */ 253 public O getObject() { 254 return object; 255 } 256 257 /** 258 * This method provides the default implementation for {@link #acceptReadLocked(FailableConsumer)}, and 259 * {@link #acceptWriteLocked(FailableConsumer)}. 260 * 261 * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used 262 * internally.) 263 * @param consumer The consumer, which is to be given access to the locked (hidden) object, which will be passed 264 * as a parameter. 265 * @see #acceptReadLocked(FailableConsumer) 266 * @see #acceptWriteLocked(FailableConsumer) 267 */ 268 protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) { 269 final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock"); 270 lock.lock(); 271 try { 272 if (consumer != null) { 273 consumer.accept(object); 274 } 275 } catch (final Throwable t) { 276 throw Failable.rethrow(t); 277 } finally { 278 lock.unlock(); 279 } 280 } 281 282 /** 283 * This method provides the actual implementation for {@link #applyReadLocked(FailableFunction)}, and 284 * {@link #applyWriteLocked(FailableFunction)}. 285 * 286 * @param <T> The result type (both the functions, and this method's.) 287 * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used 288 * internally.) 289 * @param function The function, which is being invoked to compute the result object. This function will receive 290 * the locked (hidden) object as a parameter. 291 * @return The result object, which has been returned by the functions invocation. 292 * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend 293 * access to the hidden object beyond this methods lifetime and will therefore be prevented. 294 * @see #applyReadLocked(FailableFunction) 295 * @see #applyWriteLocked(FailableFunction) 296 */ 297 protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) { 298 final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock"); 299 lock.lock(); 300 try { 301 return function.apply(object); 302 } catch (final Throwable t) { 303 throw Failable.rethrow(t); 304 } finally { 305 lock.unlock(); 306 } 307 } 308 309 } 310 311 /** 312 * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic 313 * idea, is that the user code forsakes all references to the locked object, using only the wrapper object, and the 314 * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)}, 315 * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the 316 * necessary protections are guaranteed. 317 * 318 * @param <O> The locked (hidden) objects type. 319 */ 320 public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> { 321 322 /** 323 * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing 324 * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead. 325 * 326 * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object. 327 * @param readWriteLock the lock to use. 328 */ 329 protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) { 330 super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock); 331 } 332 } 333 334 /** 335 * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic 336 * idea is that the user code forsakes all references to the locked object, using only the wrapper object, and the 337 * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)}, 338 * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the 339 * necessary protections are guaranteed. 340 * 341 * @param <O> The locked (hidden) objects type. 342 */ 343 public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> { 344 345 /** 346 * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing 347 * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead. 348 * 349 * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object. 350 * @param stampedLock the lock to use. 351 */ 352 protected StampedLockVisitor(final O object, final StampedLock stampedLock) { 353 super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock); 354 } 355 } 356 357 /** 358 * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object and lock. 359 * 360 * @param <O> The locked objects type. 361 * @param object The locked (hidden) object. 362 * @param readWriteLock The lock to use. 363 * @return The created instance, a {@link StampedLockVisitor lock} for the given object. 364 * @since 3.13.0 365 */ 366 public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) { 367 return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock); 368 } 369 370 /** 371 * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object. 372 * 373 * @param <O> The locked objects type. 374 * @param object The locked (hidden) object. 375 * @return The created instance, a {@link StampedLockVisitor lock} for the given object. 376 */ 377 public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) { 378 return create(object, new ReentrantReadWriteLock()); 379 } 380 381 /** 382 * Creates a new instance of {@link StampedLockVisitor} with the given (hidden) object. 383 * 384 * @param <O> The locked objects type. 385 * @param object The locked (hidden) object. 386 * @return The created instance, a {@link StampedLockVisitor lock} for the given object. 387 */ 388 public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) { 389 return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock()); 390 } 391 392 /** 393 * Make private in 4.0. 394 * 395 * @deprecated TODO Make private in 4.0. 396 */ 397 @Deprecated 398 public LockingVisitors() { 399 // empty 400 } 401}