1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.transaction.locking; 18 19 import org.apache.commons.transaction.util.LoggerFacade; 20 21 /** 22 * Convenience implementation of a read/write lock with an option for upgrade 23 * based on {@link ReadWriteUpgradeLock}.<br> 24 * <br> 25 * Reads are shared which means there can be any number of concurrent read 26 * accesses allowed by this lock. Writes are exclusive. This means when there is 27 * a write access no other access neither read nor write are allowed by this 28 * lock. <br> 29 * <br> 30 * <p> 31 * The idea (as explained by Jim LoVerde) on an upgrade lock is that only one owner can hold an 32 * upgrade lock, but while that is held, it is possible for read locks to exist 33 * and/or be obtained, and when the request is made to upgrade to a write lock 34 * by the same owner, the lock manager prevents additional read locks until the 35 * write lock can be aquired. 36 * </p> 37 * <p> 38 * In this sense the write lock becomes preferred over all other locks when it gets upgraded from 39 * a upgrate lock. Preferred means that if it has to wait and others wait as well it will be 40 * served before all other none preferred locking requests. 41 * </p> 42 * 43 * Calls to {@link #acquireRead(Object, long)}, {@link #acquireUpgrade(Object, long)} and 44 * {@link #acquireWrite(Object, long)} are blocking and reentrant. Blocking 45 * means they will wait if they can not acquire the descired access, reentrant 46 * means that a lock request by a specific owner will always be compatible with 47 * other accesses on this lock by the same owner. E.g. if you already have a 48 * lock for writing and you try to acquire write access again you will not be 49 * blocked by this first lock, while others of course will be. This is the 50 * natural way you already know from Java monitors and synchronized blocks. 51 * 52 * @version $Id: ReadWriteUpgradeLock.java 493628 2007-01-07 01:42:48Z joerg $ 53 * 54 * @see GenericLock 55 * @see org.apache.commons.transaction.locking.ReadWriteLock 56 * @see ReadWriteUpgradeLockManager 57 * @since 1.1 58 */ 59 public class ReadWriteUpgradeLock extends GenericLock { 60 61 public static final int NO_LOCK = 0; 62 63 public static final int READ_LOCK = 1; 64 65 public static final int UPGRADE_LOCK = 2; 66 67 public static final int WRITE_LOCK = 3; 68 69 /** 70 * Creates a new read/write/upgrade lock. 71 * 72 * @param resourceId 73 * identifier for the resource associated to this lock 74 * @param logger 75 * generic logger used for all kind of debug logging 76 */ 77 public ReadWriteUpgradeLock(Object resourceId, LoggerFacade logger) { 78 super(resourceId, WRITE_LOCK, logger); 79 } 80 81 /** 82 * Tries to acquire a blocking, reentrant read lock. A read lock is 83 * compatible with other read locks, but not with a write lock. 84 * 85 * @param ownerId 86 * a unique id identifying the entity that wants to acquire a 87 * certain lock level on this lock 88 * @param timeoutMSecs 89 * if blocking is enabled by the <code>wait</code> parameter 90 * this specifies the maximum wait time in milliseconds 91 * @return <code>true</code> if the lock actually was acquired 92 * @throws InterruptedException 93 * when the thread waiting on this method is interrupted 94 */ 95 public boolean acquireRead(Object ownerId, long timeoutMSecs) throws InterruptedException { 96 return acquire(ownerId, READ_LOCK, true, true, timeoutMSecs); 97 } 98 99 /** 100 * Tries to acquire a reentrant upgrade lock on a resource. <br> 101 * 102 * @param ownerId 103 * a unique id identifying the entity that wants to acquire a 104 * certain lock level on this lock 105 * @param timeoutMSecs 106 * if blocking is enabled by the <code>wait</code> parameter 107 * this specifies the maximum wait time in milliseconds 108 * @return <code>true</code> if the lock actually was acquired 109 * @throws InterruptedException 110 * when the thread waiting on this method is interrupted 111 */ 112 public boolean acquireUpgrade(Object ownerId, long timeoutMSecs) throws InterruptedException { 113 return acquire(ownerId, UPGRADE_LOCK, true, true, timeoutMSecs); 114 } 115 116 /** 117 * Tries to acquire a blocking, reentrant write lock. A write lock is 118 * incompatible with any another read or write lock and is thus exclusive. 119 * 120 * @param ownerId 121 * a unique id identifying the entity that wants to acquire a 122 * certain lock level on this lock 123 * @param timeoutMSecs 124 * if blocking is enabled by the <code>wait</code> parameter 125 * this specifies the maximum wait time in milliseconds 126 * @return <code>true</code> if the lock actually was acquired 127 * @throws InterruptedException 128 * when the thread waiting on this method is interrupted 129 */ 130 public boolean acquireWrite(Object ownerId, long timeoutMSecs) throws InterruptedException { 131 // in case we already had an upgrade lock, this wait lock will become preferred 132 boolean preferred = getLockLevel(ownerId) == UPGRADE_LOCK; 133 return acquire(ownerId, WRITE_LOCK, true, COMPATIBILITY_REENTRANT, preferred, timeoutMSecs); 134 } 135 136 /** 137 * @see GenericLock#acquire(Object, int, boolean, int, boolean, long) 138 */ 139 public synchronized boolean acquire(Object ownerId, int targetLockLevel, boolean wait, 140 int compatibility, boolean preferred, long timeoutMSecs) throws InterruptedException { 141 if (targetLockLevel == WRITE_LOCK && getLockLevel(ownerId) == UPGRADE_LOCK) { 142 preferred = true; 143 } 144 return super.acquire(ownerId, targetLockLevel, wait, compatibility, preferred, timeoutMSecs); 145 } 146 147 }