All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.zon_g.ABC.client.locks.Lock Maven / Gradle / Ivy

/**
 * Copyright 2021 the original author, Lin Tang
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.zon_g.ABC.client.locks;

import io.github.zon_g.ABC.commons.types.LockType;

/**
 * {@link Lock} implementations provides more extensive locking operations for distributed
 * application, where synchronized methods or other {@link java.util.concurrent.locks.Lock}
 * implementations can not provide locking operation. They allow more flexible structuring,
 * having quite different properties.
 * 

* Generally, a lock is a tool for controlling access to a shared resource by multiple threads. * Nevertheless, a resource can be shared by threads from multiple application in distributed * applications. Commonly, a lock provides exclusive access to a shared resource: only one thread * at a time can acquire the lock and all access to the shared resource requires that the lock be * acquired first. However, some locks may allow concurrent access to a shared resource, such as * the read lock of a {@link ReadWriteLock}. *

* With this increased flexibility comes additional responsibility. In most cases, the following * idiom should be used: * *

 *     {@code
 *     Lock l = ...;
 *     try {
 *         // access the resource protected by this lock
 *     } finally {
 *         l.unlock();
 *     }}
 * 
*

* Here, locking and unlocking are encouraged to appear in the same scope. When locking and unlocking * occur in different scopes, care must be taken to ensure that all code that is executed while the lock * is held is protected by try-finally or try-catch to ensure that the lock is released when necessary. *

* {@link Lock} implementations provide additional functionality by providing a non-blocking attempt to * acquire a lock ({@link #tryLock()}), an expiration for a lock if locking succeeds * ({@link TimeoutLock}) and reentrant usage ({@link ReentrantLock}). *

* A {@link Lock} class can also provides behavior and semantics that is quite different from that of the * implicit monitor lock, such as reentrant usage. *

* Note that {@link Lock} instances are just normal objects and can themselves be used as the target in * a synchronized statement. Acquiring the monitor lock of a {@link Lock} instance has no * specified relationship with invoking any of the {@link #lock()} methods of that instance. Thus it is * recommended that to avoid confusion you never use Lock instances in this way strongly. *

* In a distributed application, it is mandatory to specify the lock name (or lock key {@link #lockKey}) * to distinguish distributed locks with the same lock type * {@link LockType} for locking and unlocking. *

* Implementations of {@link Lock} never throw an exception when locking or unlocking fails. But it is * still strongly recommended that locking and unlocking should be used in a try-catch or * try-finally structure, avoiding lock is held forever in lock server incurred by exceptions * thrown from code access the resource protected by {@code Lock} instances. Even a lock is an instance * of {@link TimeoutLock}, it is recommended to do so. *

* Besides, {@link Lock} provides no interruption, which implies that locking can be canceled. * * @author Lin Tang * @see SimpleLock * @see ReentrantLock * @see TimeoutLock * @see ReadWriteLock * @since 1.0.0 */ public abstract class Lock { protected static final String EMPTY_LOCK_KEY = "Lock key should not be null or empty, reset lock key.", LOCKING_ALREADY = "Locking succeeds already, lock cancels.", LOCKING_FAILS = "Locking fails before, unlock cancels.", UNLOCKING_ALREADY = "Unlocking succeeds already, unlock cancels."; /** * Key to distinguish locks. */ private final String lockKey; private boolean success = false; private boolean canLock = true; private boolean canUnlock = false; Lock(String lockKey) { this.lockKey = lockKey; } /** * Acquires the lock if and only if it is free at the time of invocation. *

* Acquires the lock if it is available and returns with the value true immediately. * If the lock is not available then this method will return immediately with the value false. Namely, * {@link #tryLock()} only sends a lock request to lock server once and acquires a lock response * immediately, representing whether locking succeeds or not. *

* A typical usage idiom for this method would be: *

     *     {@code
     *     Lock lock = ...;
     *     if (lock.tryLock()) {
     *         try {
     *             // manipulate protected state
     *         } finally {
     *             lock.unlock();
     *         }
     *     } else {
     *         // perform alternative actions
     *     }}
     * 
*

* This usage ensures that the lock is unlocked if it was acquired, and does not * try to unlock if the lock was not acquired. *

* Implementation Considerations *

* Only an initialized lock instance, not support for reentrant lock, can invoke {@link #tryLock()}, * except for {@link ReentrantLock}. Once a lock instance succeeds in locking, lock request should * be intercepted and returns immediately. *

* * @return {@code true} if the lock was acquired and {@code false} otherwise. */ protected abstract boolean tryLock(); /** * Acquires the lock. *

* If the lock is not available then current thread will wait until the lock is available at lock server, * which implies the lock has been acquired. Namely, {@link #lock()} locking never fails. *

* Implementation Considerations *

* Only an initialized lock instance, not support for reentrant lock, can invoke {@link #lock()}, * except for {@link ReentrantLock}. Once a lock instance succeeds in locking, lock request should * be intercepted and returns immediately. *

* No support for interruption */ protected abstract void lock(); /** * Releases the lock. *

* Implementation Considerations *

* A Lock implementation will usually impose restrictions on which thread can release a * lock (typically only the holder of the lock, which has not been unlocked or unlocked completely * before, can invoke {@link #unlock()}). It throws no exceptions as much as possible. */ protected abstract void unlock(); /** * Validates whether lock key is available. * * @return true if lock key is available and false otherwise. */ boolean validateLockKey() { return lockKey != null && lockKey.length() > 0; } String getLockKey() { return this.lockKey; } boolean isSuccess() { return this.success; } void setSuccess(boolean success) { this.success = success; } boolean canLock() { return this.canLock; } void setCanLock(boolean canLock) { this.canLock = canLock; } boolean canUnlock() { return this.canUnlock; } void setCanUnlock(boolean canUnlock) { this.canUnlock = canUnlock; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy