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    }