    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    }