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
039package org.jfree.threads;
040
041import java.util.ArrayList;
042import 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 */
049public 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}