KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > triactive > jdo > util > ReadWriteLock


1 /*
2  * Copyright 2002 (C) TJDO.
3  * All rights reserved.
4  *
5  * This software is distributed under the terms of the TJDO License version 1.0.
6  * See the terms of the TJDO License in the documentation provided with this software.
7  *
8  * $Id: ReadWriteLock.java,v 1.3 2002/11/08 05:06:27 jackknifebarber Exp $
9  */

10
11 package com.triactive.jdo.util;
12
13 import org.apache.log4j.Category;
14
15
16 /**
17  * A simple read-write lock implementation. Multiple threads may lock using
18  * readLock(), only one can lock using writeLock(). The caller is responsible
19  * for coding a try-finally that ensures unlock() is called for every readLock()
20  * and writeLock() call.
21  *
22  * <p>A ReadWriteLock is recursive; with one exception, a thread can re-lock an
23  * object it already has locked. Multiple read locks can be acquired by the
24  * same thread, as can multiple write locks. The exception however is that a
25  * write lock cannot be acquired when a read lock is already held (to allow
26  * this would cause deadlocks).
27  *
28  * <p>Successive lock calls from the same thread must be matched by an
29  * equal number of unlock() calls.
30  *
31  * @author <a HREF="mailto:mmartin5@austin.rr.com">Mike Martin</a>
32  * @version $Revision: 1.3 $
33  */

34
35 public class ReadWriteLock
36 {
37     private static final Category LOG = Category.getInstance(ReadWriteLock.class);
38
39     private static final int WAIT_LOG_INTERVAL = 5000;
40
41     /** A count for each thread indicating the number of read locks it holds. */
42     private ThreadLocal JavaDoc readLocksByThread;
43
44     /** The number of read locks held across all threads. */
45     private int readLocks;
46
47     /** The number of write locks held (by writeLockedBy). */
48     private int writeLocks;
49
50     /** The thread holding the write lock(s), if any. */
51     private Thread JavaDoc writeLockedBy;
52
53
54     /**
55      * An object holding a per-thread read-lock count.
56      */

57
58     private static class Count
59     {
60         public int value = 0;
61     }
62
63
64     /**
65      * Constructs read-write lock.
66      */

67
68     public ReadWriteLock()
69     {
70         readLocksByThread = new ThreadLocal JavaDoc()
71             {
72                 public Object JavaDoc initialValue()
73                 {
74                     return new Count();
75                 }
76             };
77
78         readLocks = 0;
79         writeLocks = 0;
80         writeLockedBy = null;
81     }
82
83
84     /**
85      * Acquire a read lock. The calling thread will be suspended until no other
86      * thread holds a write lock.
87      *
88      * <p>If the calling thread already owns a write lock for the object a read
89      * lock is immediately acquired.
90      *
91      * @exception InterruptedException
92      * If the thread is interrupted while attempting to acquire the lock.
93      */

94
95     public synchronized void readLock() throws InterruptedException JavaDoc
96     {
97         Thread JavaDoc me = Thread.currentThread();
98         Count myReadLocks = (Count)readLocksByThread.get();
99
100         if (writeLockedBy != me)
101         {
102             while (writeLocks > 0)
103             {
104                 wait(WAIT_LOG_INTERVAL);
105
106                 if (writeLocks > 0)
107                     LOG.debug("Still waiting for read lock on " + this, new InterruptedException JavaDoc());
108             }
109         }
110
111         ++readLocks;
112         ++myReadLocks.value;
113     }
114
115
116     /**
117      * Acquire a write lock. The calling thread will be suspended until no
118      * other thread holds a read or write lock.
119      *
120      * <p>This method cannot be called if the thread already owns a read lock on
121      * the same ReadWriteLock object, otherwise an
122      * <code>IllegalStateException</code> is thrown.
123      *
124      * @exception IllegalStateException
125      * If the thread already holds a read lock on the same object.
126      * @exception InterruptedException
127      * If the thread is interrupted while attempting to acquire the lock.
128      */

129
130     public synchronized void writeLock() throws InterruptedException JavaDoc
131     {
132         Thread JavaDoc me = Thread.currentThread();
133         Count myReadLocks = (Count)readLocksByThread.get();
134
135         if (myReadLocks.value > 0)
136             throw new IllegalStateException JavaDoc("Thread already holds a read lock");
137
138         if (writeLockedBy != me)
139         {
140             while (writeLocks > 0 || readLocks > 0)
141             {
142                 wait(WAIT_LOG_INTERVAL);
143
144                 if (writeLocks > 0 || readLocks > 0)
145                     LOG.debug("Still waiting for write lock on " + this, new InterruptedException JavaDoc());
146             }
147
148             writeLockedBy = me;
149         }
150
151         ++writeLocks;
152     }
153
154
155     /**
156      * Release a read or write lock. Must be called in a finally block after
157      * acquiring a lock.
158      */

159
160     public synchronized void unlock()
161     {
162         Thread JavaDoc me = Thread.currentThread();
163         Count myReadLocks = (Count)readLocksByThread.get();
164
165         if (myReadLocks.value > 0)
166         {
167             --myReadLocks.value;
168             --readLocks;
169         }
170         else if (writeLockedBy == me)
171         {
172             if (writeLocks > 0)
173             {
174                 if (--writeLocks == 0)
175                     writeLockedBy = null;
176             }
177         }
178
179         notifyAll();
180     }
181
182
183     public String JavaDoc toString()
184     {
185         StringBuffer JavaDoc s = new StringBuffer JavaDoc(super.toString());
186
187         s.append(": readLocks = ").append(readLocks)
188          .append(", writeLocks = ").append(writeLocks)
189          .append(", writeLockedBy = ").append(writeLockedBy);
190
191         return s.toString();
192     }
193 }
194
Popular Tags