KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > DijkstraSemaphore


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9  */

10 package org.mmbase.util;
11
12 import org.mmbase.util.logging.Logger;
13 import org.mmbase.util.logging.Logging;
14 /**
15  * Also called counting semaphores, Dijkstra semaphores are used to control access to
16  * a set of resources. A Dijkstra semaphore has a count associated with it and each
17  * acquire() call reduces the count. A thread that tries to acquire() a Dijkstra
18  * semaphore with a zero count blocks until someone else calls release() thus increasing
19  * the count.
20  * <b>When to use</b>
21  * Recommended when applications require a counting semaphore. Implementing
22  * a counting semaphore using wait()/notify() and counters within your application
23  * code makes your code less readable and quickly increases the complexity
24  * (especially when you have the need for multiple counting semaphores). Can also
25  * be used to port code from POSIX environment.
26  *
27  * @author Karthik Rangaraju
28  * @author Michiel Meeuwissen
29  * @since MMBase-1.6
30  * @version $Id: DijkstraSemaphore.java,v 1.8 2005/03/16 19:06:44 michiel Exp $
31  */

32 public class DijkstraSemaphore {
33
34     private static final Logger log = Logging.getLoggerInstance(DijkstraSemaphore.class);
35
36     private int count;
37     private int maxCount;
38     private Object JavaDoc starvationLock = new Object JavaDoc();
39
40     /**
41      * Creates a Dijkstra semaphore with the specified max count and initial count set
42      * to the max count (all resources released)
43      * @param pMaxCount is the max semaphores that can be acquired
44      */

45     public DijkstraSemaphore(int pMaxCount) {
46         this(pMaxCount, pMaxCount);
47     }
48
49     /**
50      * Creates a Dijkstra semaphore with the specified max count and an initial count
51      * of acquire() operations that are assumed to have already been performed.
52      * @param pMaxCount is the max semaphores that can be acquired
53      * @param pInitialCount is the current count (setting it to zero means all semaphores
54      * have already been acquired). 0 <= pInitialCount <= pMaxCount
55      */

56     public DijkstraSemaphore(int pMaxCount, int pInitialCount) {
57         count = pInitialCount;
58         maxCount = pMaxCount;
59     }
60
61     /**
62      * If the count is non-zero, acquires a semaphore and decrements the count by 1,
63      * otherwise blocks until a release() is executed by some other thread.
64      * @throws InterruptedException if the thread is interrupted when blocked
65      * @see #tryAcquire()
66      * @see #acquireAll()
67      */

68     public synchronized void acquire() throws InterruptedException JavaDoc {
69         // Using a spin lock to take care of rogue threads that can enter
70
// before a thread that has exited the wait state acquires the monitor
71
while (count == 0) {
72             long startwait = 0;
73             if (log.isDebugEnabled()) {
74                 startwait = System.currentTimeMillis();
75             }
76             wait();
77             if (startwait != 0) {
78                 log.debug("Waited " + (System.currentTimeMillis() - startwait) + " ms for a resource");
79             }
80         }
81         count--;
82         synchronized (starvationLock) {
83             if (count == 0) {
84                 starvationLock.notify();
85             }
86         }
87     }
88
89     /**
90      * Non-blocking version of acquire().
91      * @return true if semaphore was acquired (count is decremented by 1), false
92      * otherwise
93      */

94     public synchronized boolean tryAcquire() {
95         if (count != 0) {
96             count--;
97             synchronized (starvationLock) {
98                 if (count == 0) {
99                     starvationLock.notify();
100                 }
101             }
102             return true;
103         }
104         else {
105             return false;
106         }
107     }
108
109     /**
110      * Releases a previously acquires semaphore and increments the count by one. Does not
111      * check if the thread releasing the semaphore was a thread that acquired the
112      * semaphore previously. If more releases are performed than acquires, the count is
113      * not increased beyond the max count specified during construction.
114      * @see #release(int pCount)
115      * @see #releaseAll()
116      */

117     public synchronized void release() {
118         count++;
119         if (count > maxCount) {
120             count = maxCount;
121         }
122         notify();
123     }
124
125     /**
126      * Same as release() except that the count is increased by pCount instead of 1. The
127      * resulting count is capped at max count specified in the constructor
128      * @param pCount is the amount by which the counter should be incremented
129      * @see #release()
130      */

131     public synchronized void release(int pCount) {
132         while (count < maxCount && pCount != 0){
133             release();
134             pCount --;
135         }
136     }
137
138     /**
139      * Tries to acquire all the semaphores thus bringing the count to zero.
140      * @throws InterruptedException if the thread is interrupted when blocked on this call
141      * @see #acquire()
142      * @see #releaseAll()
143      */

144     public synchronized void acquireAll() throws InterruptedException JavaDoc {
145         while(count != 0){
146             acquire();
147         }
148     }
149
150     /**
151      * Releases all semaphores setting the count to max count.
152      * Warning: If this method is called by a thread that did not make a corresponding
153      * acquireAll() call, then you better know what you are doing!
154      * @see #acquireAll()
155      */

156     public synchronized void releaseAll() {
157         release(maxCount);
158     }
159
160     /**
161      * This method blocks the calling thread until the count drops to zero.
162      * The method is not stateful and hence a drop to zero will not be recognized
163      * if a release happens before this call. You can use this method to implement
164      * threads that dynamically increase the resource pool or that log occurences
165      * of resource starvation. Also called a reverse-sensing semaphore
166      * @throws InterruptedException if the thread is interrupted while waiting
167      */

168     public void starvationCheck() throws InterruptedException JavaDoc {
169         synchronized (starvationLock) {
170             if (count != 0) {
171                 starvationLock.wait();
172             }
173         }
174     }
175 }
176
177
Popular Tags