Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

ReadPrioritaryFIFOWriteLock.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): ______________________.
00023  */
00024 
00025 package org.objectweb.cjdbc.common.util;
00026 
00027 import java.util.ArrayList;
00028 
00029 /**
00030  * Reader/Writer lock with write priority.
00031  * <p>
00032  * If a reader holds the lock, all incoming readers are allowed to acquire the
00033  * lock until a write arrives. A writer must wait for all current readers to
00034  * release the lock before acquiring it. <br>
00035  * When a writer has the lock, everybody else is blocked. <br>
00036  * When a writer release the lock, there is a writer priority so if another
00037  * writer is waiting it will have the lock even if it arrived later than
00038  * readers. Writers are prioritary against readers but all writers get the lock
00039  * in a FIFO order.
00040  * 
00041  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00042  * @version 1.0
00043  */
00044 public class ReadPrioritaryFIFOWriteLock
00045 {
00046   /** Threads executing read. */
00047   private int       activeReaders;
00048 
00049   /** Is there an active writer? */
00050   private boolean   activeWriter;
00051 
00052   /** Threads not yet in read. */
00053   private int       waitingReaders;
00054 
00055   /** Threads not yet in write. */
00056   private int       waitingWriters;
00057 
00058   private Object    readSync;
00059   private ArrayList writeWaitingQueue;
00060 
00061   /**
00062    * Creates a new <code>ReadPrioritaryFIFOWriteLock</code> instance.
00063    */
00064   public ReadPrioritaryFIFOWriteLock()
00065   {
00066     activeReaders = 0;
00067     activeWriter = false;
00068     waitingReaders = 0;
00069     waitingWriters = 0;
00070     readSync = new Object();
00071     writeWaitingQueue = new ArrayList();
00072   }
00073 
00074   /**
00075    * Acquires the lock for a read.
00076    * 
00077    * @throws InterruptedException if wait failed (the lock should remain in a
00078    *           correct state)
00079    */
00080   public void acquireRead() throws InterruptedException
00081   {
00082     synchronized (this)
00083     {
00084       if ((waitingWriters == 0) && !activeWriter)
00085       { // No active or pending writer
00086         activeReaders++;
00087         return;
00088       }
00089     }
00090 
00091     // Beyond this point, we have to wait
00092     synchronized (readSync)
00093     {
00094       // It becomes a little bit tricky here but a writer could have
00095       // released the lock between the first test at the beginning of
00096       // this function and this point. Therefore we have to recheck if
00097       // the lock is not completely idle else we'll never wake up !
00098       synchronized (this)
00099       {
00100         if (!activeWriter)
00101         { // No active or pending writer
00102           activeReaders++;
00103           return;
00104         }
00105       }
00106 
00107       waitingReaders++;
00108       try
00109       {
00110         readSync.wait();
00111       }
00112       catch (InterruptedException ie)
00113       {
00114         waitingReaders--; // roll back state
00115         throw ie;
00116       }
00117       waitingReaders--;
00118     }
00119     synchronized (this)
00120     {
00121       activeReaders++;
00122     }
00123   }
00124 
00125   /**
00126    * Releases a lock previously acquired for reading.
00127    */
00128   public synchronized void releaseRead()
00129   {
00130     activeReaders--;
00131     if ((activeReaders == 0) && (waitingWriters > 0))
00132     { // Wake up first waiting write if any
00133       Object thread = writeWaitingQueue.remove(0);
00134       synchronized (thread)
00135       {
00136         thread.notify();
00137         activeWriter = true;
00138         waitingWriters--;
00139       }
00140     }
00141   }
00142 
00143   /**
00144    * Acquires the lock for a write.
00145    * 
00146    * @throws InterruptedException if wait failed (the lock should remain in a
00147    *           correct state)
00148    */
00149   public void acquireWrite() throws InterruptedException
00150   {
00151     synchronized (Thread.currentThread())
00152     {
00153       synchronized (this)
00154       {
00155         if ((activeReaders == 0) && !activeWriter)
00156         {
00157           activeWriter = true;
00158           return;
00159         }
00160         else
00161         {
00162           waitingWriters++;
00163           writeWaitingQueue.add(Thread.currentThread());
00164         }
00165       }
00166       try
00167       {
00168         Thread.currentThread().wait();
00169       }
00170       catch (InterruptedException ie)
00171       {
00172         releaseWrite();
00173         throw ie;
00174       }
00175     }
00176   }
00177 
00178   /**
00179    * Releases a lock previously acquired for writing.
00180    */
00181   public synchronized void releaseWrite()
00182   {
00183     activeWriter = false;
00184 
00185     // Writer priority
00186     if (waitingWriters > 0)
00187     { // Wake up first waiting write if any
00188       Object thread = writeWaitingQueue.remove(0);
00189       synchronized (thread)
00190       {
00191         thread.notify();
00192         activeWriter = true;
00193         waitingWriters--;
00194       }
00195     }
00196 
00197     // Wake up readers
00198     else
00199       synchronized (readSync)
00200       {
00201         if (waitingReaders > 0)
00202           readSync.notifyAll();
00203       }
00204   }
00205 
00206   /**
00207    * Tests if the lock is currently held by at least one reader.
00208    * 
00209    * @return <code>true</code> if the lock is held by a reader
00210    */
00211   public final synchronized boolean isReadLocked()
00212   {
00213     return activeReaders > 0;
00214   }
00215 
00216   /**
00217    * Tests if the lock is currently held by a writer.
00218    * 
00219    * @return <code>true</code> if the lock is held by a writer
00220    */
00221   public final synchronized boolean isWriteLocked()
00222   {
00223     return activeWriter;
00224   }
00225 }

Generated on Mon Apr 11 22:01:34 2005 for C-JDBC by  doxygen 1.3.9.1