Java tutorial
/* * Copyright 2002 (C) TJDO. * All rights reserved. * * This software is distributed under the terms of the TJDO License version 1.0. * See the terms of the TJDO License in the documentation provided with this software. * * $Id: ReadWriteLock.java,v 1.5 2006/08/02 22:41:25 jackknifebarber Exp $ */ /** * A simple read-write lock implementation. Multiple threads may lock using * readLock(), only one can lock using writeLock(). The caller is responsible * for coding a try-finally that ensures unlock() is called for every readLock() * and writeLock() call. * * <p>A ReadWriteLock is recursive; with one exception, a thread can re-lock an * object it already has locked. Multiple read locks can be acquired by the * same thread, as can multiple write locks. The exception however is that a * write lock cannot be acquired when a read lock is already held (to allow * this would cause deadlocks). * * <p>Successive lock calls from the same thread must be matched by an * equal number of unlock() calls. * * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a> * @version $Revision: 1.5 $ */ public class ReadWriteLock { private static final int WAIT_LOG_INTERVAL = 5000; /** A count for each thread indicating the number of read locks it holds. */ private ThreadLocal readLocksByThread; /** The number of read locks held across all threads. */ private int readLocks; /** The number of write locks held (by writeLockedBy). */ private int writeLocks; /** The thread holding the write lock(s), if any. */ private Thread writeLockedBy; /** * An object holding a per-thread read-lock count. */ private static class Count { public int value = 0; } /** * Constructs read-write lock. */ public ReadWriteLock() { readLocksByThread = new ThreadLocal() { public Object initialValue() { return new Count(); } }; readLocks = 0; writeLocks = 0; writeLockedBy = null; } /** * Acquire a read lock. The calling thread will be suspended until no other * thread holds a write lock. * * <p>If the calling thread already owns a write lock for the object a read * lock is immediately acquired. * * @exception InterruptedException * If the thread is interrupted while attempting to acquire the lock. */ public synchronized void readLock() throws InterruptedException { Thread me = Thread.currentThread(); Count myReadLocks = (Count) readLocksByThread.get(); if (writeLockedBy != me) { while (writeLocks > 0) { wait(WAIT_LOG_INTERVAL); if (writeLocks > 0) System.out.println("Still waiting for read lock on "); } } ++readLocks; ++myReadLocks.value; } /** * Acquire a write lock. The calling thread will be suspended until no * other thread holds a read or write lock. * * <p>This method cannot be called if the thread already owns a read lock on * the same ReadWriteLock object, otherwise an * <code>IllegalStateException</code> is thrown. * * @exception IllegalStateException * If the thread already holds a read lock on the same object. * @exception InterruptedException * If the thread is interrupted while attempting to acquire the lock. */ public synchronized void writeLock() throws InterruptedException { Thread me = Thread.currentThread(); Count myReadLocks = (Count) readLocksByThread.get(); if (myReadLocks.value > 0) throw new IllegalStateException("Thread already holds a read lock"); if (writeLockedBy != me) { while (writeLocks > 0 || readLocks > 0) { wait(WAIT_LOG_INTERVAL); if (writeLocks > 0 || readLocks > 0) System.out.println("Still waiting for write lock on "); } writeLockedBy = me; } ++writeLocks; } /** * Release a read or write lock. Must be called in a finally block after * acquiring a lock. */ public synchronized void unlock() { Thread me = Thread.currentThread(); Count myReadLocks = (Count) readLocksByThread.get(); if (myReadLocks.value > 0) { --myReadLocks.value; --readLocks; } else if (writeLockedBy == me) { if (writeLocks > 0) { if (--writeLocks == 0) writeLockedBy = null; } } notifyAll(); } public String toString() { StringBuffer s = new StringBuffer(super.toString()); s.append(": readLocks = ").append(readLocks).append(", writeLocks = ").append(writeLocks) .append(", writeLockedBy = ").append(writeLockedBy); return s.toString(); } }