1
2
3
4
5
6
7
8
9
10 package nl.tudelft.simulation.language.concurrent;
11
12 import java.util.HashMap;
13 import java.util.Map;
14
15 /***
16 * In the Java programming language there is a lock associated with every
17 * object. The language does not provide a way to perform separate lock and
18 * unlock operations; instead, they are implicitly performed by high-level
19 * constructs that always arrange to pair such operations correctly. This
20 * Monitor class, however, provides separate monitorenter and monitorexit
21 * instructions that implement the lock and unlock operations.) <br>
22 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
23 * University of Technology </a>, the Netherlands. <br>
24 * See for project information <a
25 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
26 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
27 * License (GPL) </a>, no warranty <br>
28 *
29 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
30 * Jacobs </a>
31 * @version 1.0 Jan 15, 2004 <br>
32 * @since 1.3
33 */
34 public final class Monitor
35 {
36 /*** the locks held */
37 private static Map locks = new HashMap();
38
39 /***
40 * constructs a new Monitor
41 */
42 private Monitor()
43 {
44 super();
45
46 }
47
48 /***
49 * locks an object for the current thread
50 *
51 * @param object the object to lock
52 */
53 public static void lock(final Object object)
54 {
55 Monitor.lock(object, Thread.currentThread());
56 }
57
58 /***
59 * locks an object for the given requestor.
60 *
61 * @param object the object to lock.
62 * @param requestor the requesting thread.
63 */
64 public static void lock(final Object object, final Thread requestor)
65 {
66 synchronized (Monitor.locks)
67 {
68 if (!Monitor.locks.containsKey(object))
69 {
70 Monitor.locks.put(object, new MonitorThread(requestor, object));
71 } else
72 {
73 MonitorThread thread = (MonitorThread) Monitor.locks
74 .get(object);
75 if (thread.getOwner().equals(requestor))
76 {
77 thread.increaseCounter();
78 } else
79 {
80 synchronized (object)
81 {
82
83 Monitor.locks.put(object, new MonitorThread(requestor,
84 object));
85 }
86 }
87 }
88 }
89 }
90
91 /***
92 * unlocks an object locked by the current Thread
93 *
94 * @param object the object to unlock
95 */
96 public static void unlock(final Object object)
97 {
98 Monitor.unlock(object, Thread.currentThread());
99 }
100
101 /***
102 * unlocks an object locked by owner.
103 *
104 * @param object the object to unlock.
105 * @param owner the owning thread.
106 */
107 public static void unlock(final Object object, final Thread owner)
108 {
109 synchronized (Monitor.locks)
110 {
111 MonitorThread thread = (MonitorThread) Monitor.locks.get(object);
112 if (thread == null)
113 {
114 throw new IllegalMonitorStateException("object(" + object
115 + ") is not locked");
116 }
117 if (!thread.getOwner().equals(owner))
118 {
119 throw new IllegalMonitorStateException(owner + " cannot"
120 + " unlock object owned by " + 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 * A MonitorThread is used to lock an object
133 */
134 private static class MonitorThread extends Thread
135 {
136 /*** the monitor to use */
137 private Object object = null;
138
139 /*** the owning thread */
140 private Thread owner = null;
141
142 /*** the counter */
143 private int counter = 0;
144
145 /***
146 * constructs a new MonitorThread
147 *
148 * @param owner the owning thread
149 * @param object the object
150 */
151 public MonitorThread(final Thread owner, final Object object)
152 {
153 super("MonitorThread on " + object.getClass());
154 this.setDaemon(true);
155 this.owner = owner;
156 synchronized (object)
157 {
158 this.object = object;
159 this.counter++;
160 this.start();
161 }
162 synchronized (owner)
163 {
164 try
165 {
166 this.owner.wait();
167 } catch (InterruptedException exception)
168 {
169 exception = null;
170
171
172
173
174 }
175 }
176 }
177
178 /***
179 * @return Returns the counter.
180 */
181 public synchronized int getCounter()
182 {
183 return this.counter;
184 }
185
186 /***
187 * decreases the counter with one
188 */
189 public synchronized void decreaseCounter()
190 {
191 this.counter = Math.max(0, this.counter - 1);
192 }
193
194 /***
195 * increases the counter of this thread with one
196 */
197 public synchronized void increaseCounter()
198 {
199 this.counter++;
200 }
201
202 /***
203 * @return Returns the owning thread.
204 */
205 public Thread getOwner()
206 {
207 return this.owner;
208 }
209
210 /***
211 * @see java.lang.Runnable#run()
212 */
213 public void run()
214 {
215 try
216 {
217
218 synchronized (this.object)
219 {
220
221
222 this.owner.interrupt();
223
224
225 this.join();
226 }
227 } catch (Exception exception)
228 {
229
230
231 exception = null;
232 }
233 }
234 }
235 }