KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > common > util > ReadPrioritaryFIFOWriteLock


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): ______________________.
23  */

24
25 package org.objectweb.cjdbc.common.util;
26
27 import java.util.ArrayList JavaDoc;
28
29 /**
30  * Reader/Writer lock with write priority.
31  * <p>
32  * If a reader holds the lock, all incoming readers are allowed to acquire the
33  * lock until a write arrives. A writer must wait for all current readers to
34  * release the lock before acquiring it. <br>
35  * When a writer has the lock, everybody else is blocked. <br>
36  * When a writer release the lock, there is a writer priority so if another
37  * writer is waiting it will have the lock even if it arrived later than
38  * readers. Writers are prioritary against readers but all writers get the lock
39  * in a FIFO order.
40  *
41  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
42  * @version 1.0
43  */

44 public class ReadPrioritaryFIFOWriteLock
45 {
46   /** Threads executing read. */
47   private int activeReaders;
48
49   /** Is there an active writer? */
50   private boolean activeWriter;
51
52   /** Threads not yet in read. */
53   private int waitingReaders;
54
55   /** Threads not yet in write. */
56   private int waitingWriters;
57
58   private Object JavaDoc readSync;
59   private ArrayList JavaDoc writeWaitingQueue;
60
61   /**
62    * Creates a new <code>ReadPrioritaryFIFOWriteLock</code> instance.
63    */

64   public ReadPrioritaryFIFOWriteLock()
65   {
66     activeReaders = 0;
67     activeWriter = false;
68     waitingReaders = 0;
69     waitingWriters = 0;
70     readSync = new Object JavaDoc();
71     writeWaitingQueue = new ArrayList JavaDoc();
72   }
73
74   /**
75    * Acquires the lock for a read.
76    *
77    * @throws InterruptedException if wait failed (the lock should remain in a
78    * correct state)
79    */

80   public void acquireRead() throws InterruptedException JavaDoc
81   {
82     synchronized (this)
83     {
84       if ((waitingWriters == 0) && !activeWriter)
85       { // No active or pending writer
86
activeReaders++;
87         return;
88       }
89     }
90
91     // Beyond this point, we have to wait
92
synchronized (readSync)
93     {
94       // It becomes a little bit tricky here but a writer could have
95
// released the lock between the first test at the beginning of
96
// this function and this point. Therefore we have to recheck if
97
// the lock is not completely idle else we'll never wake up !
98
synchronized (this)
99       {
100         if (!activeWriter)
101         { // No active or pending writer
102
activeReaders++;
103           return;
104         }
105       }
106
107       waitingReaders++;
108       try
109       {
110         readSync.wait();
111       }
112       catch (InterruptedException JavaDoc ie)
113       {
114         waitingReaders--; // roll back state
115
throw ie;
116       }
117       waitingReaders--;
118     }
119     synchronized (this)
120     {
121       activeReaders++;
122     }
123   }
124
125   /**
126    * Releases a lock previously acquired for reading.
127    */

128   public synchronized void releaseRead()
129   {
130     activeReaders--;
131     if ((activeReaders == 0) && (waitingWriters > 0))
132     { // Wake up first waiting write if any
133
Object JavaDoc thread = writeWaitingQueue.remove(0);
134       synchronized (thread)
135       {
136         thread.notify();
137         activeWriter = true;
138         waitingWriters--;
139       }
140     }
141   }
142
143   /**
144    * Acquires the lock for a write.
145    *
146    * @throws InterruptedException if wait failed (the lock should remain in a
147    * correct state)
148    */

149   public void acquireWrite() throws InterruptedException JavaDoc
150   {
151     synchronized (Thread.currentThread())
152     {
153       synchronized (this)
154       {
155         if ((activeReaders == 0) && !activeWriter)
156         {
157           activeWriter = true;
158           return;
159         }
160         else
161         {
162           waitingWriters++;
163           writeWaitingQueue.add(Thread.currentThread());
164         }
165       }
166       try
167       {
168         Thread.currentThread().wait();
169       }
170       catch (InterruptedException JavaDoc ie)
171       {
172         releaseWrite();
173         throw ie;
174       }
175     }
176   }
177
178   /**
179    * Releases a lock previously acquired for writing.
180    */

181   public void releaseWrite()
182   {
183     activeWriter = false;
184
185     // Writer priority
186
synchronized (this)
187     {
188       if (waitingWriters > 0)
189       { // Wake up first waiting write if any
190
Object JavaDoc thread = writeWaitingQueue.remove(0);
191         synchronized (thread)
192         {
193           thread.notify();
194           activeWriter = true;
195           waitingWriters--;
196         }
197         return;
198       }
199     }
200
201     // Wake up readers
202
//
203
// Note that we cannot do the following inside synchronized(this) because
204
// acquireRead() takes synchronized(readSync) first and then
205
// synchronized(this).
206
synchronized (readSync)
207     {
208       if (waitingReaders > 0)
209         readSync.notifyAll();
210     }
211   }
212
213   /**
214    * Tests if the lock is currently held by at least one reader.
215    *
216    * @return <code>true</code> if the lock is held by a reader
217    */

218   public final synchronized boolean isReadLocked()
219   {
220     return activeReaders > 0;
221   }
222
223   /**
224    * Tests if the lock is currently held by a writer.
225    *
226    * @return <code>true</code> if the lock is held by a writer
227    */

228   public final synchronized boolean isWriteLocked()
229   {
230     return activeWriter;
231   }
232 }
Popular Tags