    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    }