KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > util > Semaphore


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.util;
23
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.io.StringWriter JavaDoc;
29 import java.io.PrintWriter JavaDoc;
30
31 /**
32  * Semaphore that can allow a specified number of threads to enter, blocking the
33  * others. If the specified number of threads is 1, it acts as an exclusive semaphore
34  * and can be used instead of synchronized blocks
35  *
36  * @author <a HREF="mailto:simone.bordet@compaq.com">Simone Bordet</a>
37  * @version $Revision: 1958 $
38  */

39 public class Semaphore
40    implements Sync
41 {
42    // Constants -----------------------------------------------------
43
private static final long DEADLOCK_TIMEOUT = 5*60*1000;
44
45    // Attributes ----------------------------------------------------
46
private final static boolean m_debug = false;
47    private int m_users;
48    private int m_allowed;
49    private Map JavaDoc m_logMap;
50
51    // Static --------------------------------------------------------
52

53    // Constructors --------------------------------------------------
54
public Semaphore(int allowed)
55    {
56       if (allowed < 1) throw new IllegalArgumentException JavaDoc();
57         
58       m_users = 0;
59       m_allowed = allowed;
60       m_logMap = new HashMap JavaDoc();
61    }
62
63    // Public --------------------------------------------------------
64
public int getUsers()
65    {
66       synchronized (this)
67       {
68          return m_users;
69       }
70    }
71
72    // Sync implementation ----------------------------------------------
73
public void acquire() throws InterruptedException JavaDoc
74    {
75       synchronized (this)
76       {
77          logAcquire();
78             
79          // One user more called acquire, increase users
80
++m_users;
81          boolean waitSuccessful = false;
82          while (m_allowed <= 0)
83          {
84             waitSuccessful = waitImpl(this);
85             if (!waitSuccessful)
86             {
87                // Dealock was detected, restore status, 'cause it's like a release()
88
// that will probably be never called
89
--m_users;
90                ++m_allowed;
91             }
92          }
93          --m_allowed;
94       }
95    }
96
97    public void release()
98    {
99       synchronized (this)
100       {
101          logRelease();
102             
103          --m_users;
104          ++m_allowed;
105          notify();
106       }
107    }
108
109    // Object overrides ---------------------------------------------------
110
public String JavaDoc toString()
111    {
112       return super.toString() + " - " + m_users;
113    }
114
115    // Package protected ---------------------------------------------
116

117    // Protected -----------------------------------------------------
118
protected boolean waitImpl(Object JavaDoc lock) throws InterruptedException JavaDoc
119    {
120       // Wait (forever) until notified. To discover deadlocks,
121
// turn on debugging of this class
122
long start = System.currentTimeMillis();
123       lock.wait(DEADLOCK_TIMEOUT);
124       long end = System.currentTimeMillis();
125
126       if ((end - start) > (DEADLOCK_TIMEOUT - 1000))
127       {
128          logDeadlock();
129          return false;
130       }
131       return true;
132    }
133     
134    protected void logAcquire()
135    {
136       if (m_debug)
137       {
138          // Check if thread is already mapped
139
Thread JavaDoc thread = Thread.currentThread();
140
141          // Create stack trace
142
StringWriter JavaDoc sw = new StringWriter JavaDoc();
143          new Exception JavaDoc().printStackTrace(new PrintWriter JavaDoc(sw));
144          String JavaDoc trace = sw.toString();
145         
146          LinkedList JavaDoc list = (LinkedList JavaDoc)m_logMap.get(thread);
147          if (list != null)
148          {
149             // Thread is mapped
150
// Add info
151
Info prevInfo = (Info)list.getLast();
152             Info info = new Info(thread, m_users, trace);
153             list.add(info);
154          }
155          else
156          {
157             // Thread is not mapped, create list and add counter
158
list = new LinkedList JavaDoc();
159             Info info = new Info(thread, m_users, trace);
160             list.add(info);
161             // Map thread
162
m_logMap.put(thread, list);
163          }
164       }
165    }
166    protected void logDeadlock()
167    {
168       System.err.println();
169       System.err.println("DEADLOCK ON SEMAPHORE " + this);
170       if (m_debug)
171       {
172          for (Iterator JavaDoc i = m_logMap.values().iterator(); i.hasNext();)
173          {
174             LinkedList JavaDoc list = (LinkedList JavaDoc)i.next();
175             for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();)
176             {
177                System.err.println(iter.next());
178             }
179          }
180       }
181       System.err.println();
182    }
183    protected void logRelease()
184    {
185       if (m_debug)
186       {
187          // Find a matching thread and remove info for it
188
Thread JavaDoc thread = Thread.currentThread();
189
190          LinkedList JavaDoc list = (LinkedList JavaDoc)m_logMap.get(thread);
191          if (list != null)
192          {
193             Info info = new Info(thread, 0, "");
194             if (!list.remove(info))
195             {
196                System.err.println("LOG INFO SIZE: " + list);
197                new IllegalStateException JavaDoc("BUG: semaphore log list does not contain required info").printStackTrace();
198             }
199
200             // If no info left, remove the mapping
201
int size = list.size();
202             if (size < 1)
203             {
204                m_logMap.remove(thread);
205             }
206          }
207          else
208          {
209             throw new IllegalStateException JavaDoc("Semaphore log failed: release called without acquire");
210          }
211       }
212    }
213
214    // Private -------------------------------------------------------
215

216    // Inner classes -------------------------------------------------
217
private class Info
218    {
219       private Info(Thread JavaDoc t, int i, String JavaDoc s)
220       {
221          m_thread = t;
222          m_counter = i;
223          m_trace = s;
224       }
225       private Thread JavaDoc m_thread;
226       private int m_counter;
227       private String JavaDoc m_trace;
228       public boolean equals(Object JavaDoc o)
229       {
230          Info other = (Info)o;
231          return m_thread == other.m_thread;
232       }
233       public String JavaDoc toString()
234       {
235          return m_thread + " - " + m_counter + "\n" + m_trace;
236       }
237    }
238 }
239
Popular Tags