/** * JADE - Java Agent DEvelopment Framework is a framework to develop * multi-agent systems in compliance with the FIPA specifications. * Copyright (C) 2000 CSELT S.p.A. * Copyright (C) 2001,2002 TILab S.p.A. * * GNU Lesser General Public License * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package jade.util; //#APIDOC_EXCLUDE_FILE /** * This class provides support for * synchronizing threads acting on a generic resource in such a way that * - If a thread is writing the resource no other thread can act on it * in any way * - Several threads can read the resource at the same time * - If one or more threads are reading the resource no thread can write it * @author Giovanni Caire - TILab */ public class RWLock { // The counter of threads currently reading the resource private int readersCnt = 0; // The Thread currently writing the resource (there can only be // one such a therad at a given time) private Thread currentWriter = null; // writeLock()/unlock() can be nested. This indicates the current // depth private int writeLockDepth = 0; private Logger logger = Logger.getMyLogger(this.getClass().getName()); /** Default constructor. */ public RWLock() { } /** Acquire the protected resource with writing privileges. Only one writer at a time can access the protected resource, and no readers can access it at the same time. The locking is recursive (i.e. the same thread can acquire the lock multiple times, but must unlock it a matching number of times to actually free the protected resource). */ public synchronized void writeLock() { Thread me = Thread.currentThread(); while ((currentWriter != null && currentWriter != me) || readersCnt > 0) { // Someone (not me) is writing the resource OR // There are one or more Threads reading the resource // --> Go to sleep try { wait(); } catch (InterruptedException ie) { if(logger.isLoggable(Logger.WARNING)) logger.log(Logger.WARNING,"Unexpected interruption. "+ie.getMessage()); } } writeLockDepth++; if (writeLockDepth == 1) { currentWriter = me; onWriteStart(); } } /** Release the protected resource, previously acquired with writing privileges. */ public synchronized void writeUnlock() { if (Thread.currentThread() == currentWriter) { writeLockDepth--; if (writeLockDepth == 0) { // I have finished writing the resource --> Wake up hanging threads currentWriter = null; notifyAll(); onWriteEnd(); } } } /** Acquire the protected resource with reading privileges. Many readers can access the protected resource at the same time, but no writer can access it while at least one reader is present. The locking is recursive (i.e. the same thread can acquire the lock multiple times, but must unlock it a matching number of times to actually free the protected resource). */ public synchronized void readLock() { while (currentWriter != null) { // Someone is writing the resource --> Go to sleep try { wait(); } catch (InterruptedException ie) { if(logger.isLoggable(Logger.WARNING)) logger.log(Logger.WARNING,"Unexpected interruption. "+ie.getMessage()); } } readersCnt++; } /** Release the protected resource, previously acquired with reading privileges. */ public synchronized void readUnlock() { readersCnt--; if (readersCnt == 0) { // No one is reading the resource anymore --> Wake up threads // waiting to write it notifyAll(); } } /** This placeholder method is called every time a thread actually acquires the protected resource with writing privileges (this means that, in case of multiple recursive locking by the same thread, this method is called only the first time). Subclasses can exploit this to transparently trigger a resource acquisition prolog. */ protected void onWriteStart() { } /** This placeholder method is called every time a thread actually releases the protected resource with writing privileges (this means that, in case of multiple recursive unlocking by the same thread, this method is called only the last time). Subclasses can exploit this to transparently trigger a resource release epilog. */ protected void onWriteEnd() { } }