001 // Copyright 2012 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.ioc.internal.util;
016
017 import java.util.concurrent.locks.Lock;
018 import java.util.concurrent.locks.ReentrantReadWriteLock;
019
020 /**
021 * Base class for classes that need to manage a ReadWriteLock.
022 */
023 public abstract class LockSupport
024 {
025 private final Lock readLock, writeLock;
026
027 protected LockSupport()
028 {
029 ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
030
031 readLock = lock.readLock();
032 writeLock = lock.writeLock();
033 }
034
035 /**
036 * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
037 */
038 protected final void acquireReadLock()
039 {
040 readLock.lock();
041 }
042
043 /**
044 * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
045 * this thread will have locked the write lock and no other thread will have either the read or write lock.
046 * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
047 */
048 protected final void takeWriteLock()
049 {
050 writeLock.lock();
051 }
052
053 /**
054 * Releases the shared read lock.
055 */
056 protected final void releaseReadLock()
057 {
058 readLock.unlock();
059 }
060
061 /**
062 * Releases the exclusive read lock.
063 */
064 protected final void releaseWriteLock()
065 {
066 writeLock.unlock();
067 }
068
069 /**
070 * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
071 * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
072 * inside the code that has the write lock to see if the update to perform is still necessary.
073 */
074 protected final void upgradeReadLockToWriteLock()
075 {
076 releaseReadLock();
077 // This is that instant where another thread may grab the write lock. Very rare, but possible.
078 takeWriteLock();
079 }
080
081 /**
082 * Takes the read lock then releases the write lock.
083 */
084 protected final void downgradeWriteLockToReadLock()
085 {
086 acquireReadLock();
087 releaseWriteLock();
088 }
089 }