001 /* ========================================================================
002 * JCommon : a free general purpose class library for the Java(tm) platform
003 * ========================================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jcommon/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------------
028 * ReaderWriterLock.java
029 * ---------------------
030 *
031 * $Id: ReaderWriterLock.java,v 1.3 2005/10/18 13:18:34 mungady Exp $
032 *
033 * Changes
034 * -------
035 * 29-Jan-2003 : Added standard header (DG);
036 *
037 */
038
039 package org.jfree.threads;
040
041 import java.util.ArrayList;
042 import java.util.Iterator;
043
044 /**
045 * A reader-writer lock from "Java Threads" by Scott Oak and Henry Wong.
046 *
047 * @author Scott Oak and Henry Wong
048 */
049 public class ReaderWriterLock {
050
051 /**
052 * A node for the waiting list.
053 *
054 * @author Scott Oak and Henry Wong
055 */
056 private static class ReaderWriterNode {
057
058 /** A reader. */
059 protected static final int READER = 0;
060
061 /** A writer. */
062 protected static final int WRITER = 1;
063
064 /** The thread. */
065 protected Thread t;
066
067 /** The state. */
068 protected int state;
069
070 /** The number of acquires.*/
071 protected int nAcquires;
072
073 /**
074 * Creates a new node.
075 *
076 * @param t the thread.
077 * @param state the state.
078 */
079 private ReaderWriterNode(final Thread t, final int state) {
080 this.t = t;
081 this.state = state;
082 this.nAcquires = 0;
083 }
084
085 }
086
087 /** The waiting threads. */
088 private ArrayList waiters;
089
090 /**
091 * Default constructor.
092 */
093 public ReaderWriterLock() {
094 this.waiters = new ArrayList();
095 }
096
097 /**
098 * Grab the read lock.
099 */
100 public synchronized void lockRead() {
101 final ReaderWriterNode node;
102 final Thread me = Thread.currentThread();
103 final int index = getIndex(me);
104 if (index == -1) {
105 node = new ReaderWriterNode(me, ReaderWriterNode.READER);
106 this.waiters.add(node);
107 }
108 else {
109 node = (ReaderWriterNode) this.waiters.get(index);
110 }
111 while (getIndex(me) > firstWriter()) {
112 try {
113 wait();
114 }
115 catch (Exception e) {
116 System.err.println("ReaderWriterLock.lockRead(): exception.");
117 System.err.print(e.getMessage());
118 }
119 }
120 node.nAcquires++;
121 }
122
123 /**
124 * Grab the write lock.
125 */
126 public synchronized void lockWrite() {
127 final ReaderWriterNode node;
128 final Thread me = Thread.currentThread();
129 final int index = getIndex(me);
130 if (index == -1) {
131 node = new ReaderWriterNode(me, ReaderWriterNode.WRITER);
132 this.waiters.add(node);
133 }
134 else {
135 node = (ReaderWriterNode) this.waiters.get(index);
136 if (node.state == ReaderWriterNode.READER) {
137 throw new IllegalArgumentException("Upgrade lock");
138 }
139 node.state = ReaderWriterNode.WRITER;
140 }
141 while (getIndex(me) != 0) {
142 try {
143 wait();
144 }
145 catch (Exception e) {
146 System.err.println("ReaderWriterLock.lockWrite(): exception.");
147 System.err.print(e.getMessage());
148 }
149 }
150 node.nAcquires++;
151 }
152
153 /**
154 * Unlock.
155 */
156 public synchronized void unlock() {
157
158 final ReaderWriterNode node;
159 final Thread me = Thread.currentThread();
160 final int index = getIndex(me);
161 if (index > firstWriter()) {
162 throw new IllegalArgumentException("Lock not held");
163 }
164 node = (ReaderWriterNode) this.waiters.get(index);
165 node.nAcquires--;
166 if (node.nAcquires == 0) {
167 this.waiters.remove(index);
168 }
169 notifyAll();
170 }
171
172 /**
173 * Returns the index of the first waiting writer.
174 *
175 * @return The index.
176 */
177 private int firstWriter() {
178 final Iterator e = this.waiters.iterator();
179 int index = 0;
180 while (e.hasNext()) {
181 final ReaderWriterNode node = (ReaderWriterNode) e.next();
182 if (node.state == ReaderWriterNode.WRITER) {
183 return index;
184 }
185 index += 1;
186 }
187 return Integer.MAX_VALUE;
188 }
189
190 /**
191 * Returns the index of a thread.
192 *
193 * @param t the thread.
194 *
195 * @return The index.
196 */
197 private int getIndex(final Thread t) {
198 final Iterator e = this.waiters.iterator();
199 int index = 0;
200 while (e.hasNext()) {
201 final ReaderWriterNode node = (ReaderWriterNode) e.next();
202 if (node.t == t) {
203 return index;
204 }
205 index += 1;
206 }
207 return -1;
208 }
209
210 }