/**
* 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() {
}
}