1
2
3
4
5
6 package nl.tudelft.simulation.language.concurrent;
7
8 import java.util.ArrayList;
9 import java.util.List;
10
11 /***
12 * In the Java programming language there is a lock associated with every object. The language does not
13 * provide a way to perform separate lock and unlock operations; instead, they are implicitly performed by
14 * high-level constructs that always arrange to pair such operations correctly. This Monitor class, however,
15 * provides separate monitorenter and monitorexit instructions that implement the lock and unlock operations.)
16 * <p>
17 * (c) copyright 2002-2005 <a href="http://www.simulation.tudelft.nl">Delft University of Technology </a>, the
18 * Netherlands.
19 * <p>
20 * See for project information <a
21 * href="http://www.simulation.tudelft.nl/dsol/language">www.simulation.tudelft.nl/language </a> <br>
22 * License of use: <a href="http://www.gnu.org/copyleft/lesser.html">Lesser General Public License (LGPL)
23 * </a>, no warranty
24 *
25 * @author <a href="http://www.peter-jacobs.com">Peter Jacobs </a>
26 * @version $Revision: 1.9 $ $Date: 2005/08/04 12:08:56 $
27 * @since 1.5
28 */
29 public final class Monitor
30 {
31 /*** the locks held. */
32 private static List<Monitor.Entry> locks = new ArrayList<Monitor.Entry>();
33
34 /***
35 * constructs a new Monitor.
36 */
37 private Monitor()
38 {
39 super();
40
41 }
42
43 /***
44 * locks an object for the current thread.
45 *
46 * @param object
47 * the object to lock
48 */
49 public static void lock(final Object object)
50 {
51 Monitor.lock(object, Thread.currentThread());
52 }
53
54 /***
55 * locks an object for the given requestor.
56 *
57 * @param object
58 * the object to lock.
59 * @param requestor
60 * the requesting thread.
61 */
62 public static void lock(final Object object, final Thread requestor)
63 {
64 synchronized (Monitor.locks)
65 {
66 if (Monitor.get(object) == null)
67 {
68 Monitor.locks.add(new Entry(object, new MonitorThread(requestor, object)));
69 }
70 else
71 {
72 MonitorThread thread = Monitor.get(object);
73 if (thread.getOwner().equals(requestor))
74 {
75 thread.increaseCounter();
76 }
77 else
78 {
79 synchronized (object)
80 {
81
82 Monitor.locks.add(new Entry(object, new MonitorThread(requestor, object)));
83 }
84 }
85 }
86 }
87 }
88
89 /***
90 * unlocks an object locked by the current Thread.
91 *
92 * @param object
93 * the object to unlock
94 */
95 public static void unlock(final Object object)
96 {
97 Monitor.unlock(object, Thread.currentThread());
98 }
99
100 /***
101 * unlocks an object locked by owner.
102 *
103 * @param object
104 * the object to unlock.
105 * @param owner
106 * the owning thread.
107 */
108 public static void unlock(final Object object, final Thread owner)
109 {
110 synchronized (Monitor.locks)
111 {
112 MonitorThread thread = Monitor.get(object);
113 if (thread == null)
114 {
115 throw new IllegalMonitorStateException("object(" + object + ") is not locked");
116 }
117 if (!thread.getOwner().equals(owner))
118 {
119 throw new IllegalMonitorStateException(owner + " cannot" + " unlock object owned by "
120 + thread.getOwner());
121 }
122 thread.decreaseCounter();
123 if (thread.getCounter() == 0)
124 {
125 thread.interrupt();
126 Monitor.locks.remove(object);
127 }
128 }
129 }
130
131 /***
132 * returns the MonitorThread for a specific key.
133 *
134 * @param key
135 * the key to resolve
136 * @return the MonitorThread
137 */
138 private static MonitorThread get(final Object key)
139 {
140 for (Entry next : Monitor.locks)
141 {
142 if (next.getKey().equals(key))
143 {
144 return next.getThread();
145 }
146 }
147 return null;
148 }
149
150 /***
151 * The Entry specifies entries in the set.
152 */
153 private static final class Entry
154 {
155 /*** the key to use. */
156 private Object key = null;
157
158 /*** the monitorThread. */
159 private MonitorThread thread = null;
160
161 /***
162 * constructs a new Entry.
163 *
164 * @param key
165 * the key that locked the thread
166 * @param thread
167 * the thread to be locked
168 */
169 public Entry(final Object key, final MonitorThread thread)
170 {
171 super();
172 this.key = key;
173 this.thread = thread;
174 }
175
176 /***
177 * @return the key that is locked by a thread
178 */
179 public Object getKey()
180 {
181 return this.key;
182 }
183
184 /***
185 * @return the thread that locked the key
186 */
187 public MonitorThread getThread()
188 {
189 return this.thread;
190 }
191 }
192
193 /***
194 * A MonitorThread is used to lock an object.
195 */
196 private static class MonitorThread extends Thread
197 {
198 /*** the monitor to use. */
199 private Object object = null;
200
201 /*** the owning thread. */
202 private Thread owner = null;
203
204 /*** the counter. */
205 private int counter = 0;
206
207 /***
208 * constructs a new MonitorThread.
209 *
210 * @param owner
211 * the owning thread
212 * @param object
213 * the object
214 */
215 public MonitorThread(final Thread owner, final Object object)
216 {
217 super("MonitorThread on " + object.getClass());
218 this.setDaemon(true);
219 this.owner = owner;
220 synchronized (object)
221 {
222 this.object = object;
223 this.counter++;
224 this.start();
225 }
226 synchronized (owner)
227 {
228 try
229 {
230 this.owner.wait();
231 }
232 catch (InterruptedException exception)
233 {
234 exception = null;
235
236
237
238
239 }
240 }
241 }
242
243 /***
244 * @return Returns the counter.
245 */
246 public synchronized int getCounter()
247 {
248 return this.counter;
249 }
250
251 /***
252 * decreases the counter with one.
253 */
254 public synchronized void decreaseCounter()
255 {
256 this.counter = Math.max(0, this.counter - 1);
257 }
258
259 /***
260 * increases the counter of this thread with one.
261 */
262 public synchronized void increaseCounter()
263 {
264 this.counter++;
265 }
266
267 /***
268 * @return Returns the owning thread.
269 */
270 public Thread getOwner()
271 {
272 return this.owner;
273 }
274
275 /***
276 * @see java.lang.Runnable#run()
277 */
278 @Override
279 public void run()
280 {
281 try
282 {
283
284 synchronized (this.object)
285 {
286
287
288 this.owner.interrupt();
289
290
291 this.join();
292 }
293 }
294 catch (Exception exception)
295 {
296
297
298 exception = null;
299 }
300 }
301 }
302 }