1 package nl.tudelft.simulation.language.concurrent;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 public final class Monitor
23 {
24
25 private static Map<Object, MonitorThread> locks = new LinkedHashMap<>();
26
27
28
29
30 private Monitor()
31 {
32
33 }
34
35
36
37
38
39 public static void lock(final Object object)
40 {
41 Monitor.lock(object, Thread.currentThread());
42 }
43
44
45
46
47
48
49 public static void lock(final Object object, final Thread requestor)
50 {
51 synchronized (Monitor.locks)
52 {
53 if (Monitor.get(object) == null)
54 {
55 Monitor.locks.put(object, new MonitorThread(requestor, object));
56 }
57 else
58 {
59 MonitorThread thread = Monitor.get(object);
60 if (thread.getOwner().equals(requestor))
61 {
62 thread.increaseCounter();
63 }
64 else
65 {
66 synchronized (object)
67 {
68
69 Monitor.locks.put(object, new MonitorThread(requestor, object));
70 }
71 }
72 }
73 }
74 }
75
76
77
78
79
80 public static void unlock(final Object object)
81 {
82 Monitor.unlock(object, Thread.currentThread());
83 }
84
85
86
87
88
89
90 public static void unlock(final Object object, final Thread owner)
91 {
92 synchronized (Monitor.locks)
93 {
94 MonitorThread thread = Monitor.get(object);
95 if (thread == null)
96 {
97 throw new IllegalMonitorStateException("object(" + object + ") is not locked");
98 }
99 if (!thread.getOwner().equals(owner))
100 {
101 throw new IllegalMonitorStateException(owner + " cannot" + " unlock object owned by " + thread.getOwner());
102 }
103 thread.decreaseCounter();
104 if (thread.getCounter() == 0)
105 {
106 thread.interrupt();
107 Monitor.locks.remove(object);
108 }
109 }
110 }
111
112
113
114
115
116
117 private static MonitorThread get(final Object key)
118 {
119 return locks.get(key);
120 }
121
122
123
124
125 private static class MonitorThread extends Thread
126 {
127
128 private Object object = null;
129
130
131 private Thread owner = null;
132
133
134 private int counter = 0;
135
136
137
138
139
140
141 MonitorThread(final Thread owner, final Object object)
142 {
143 super("MonitorThread on " + object.getClass());
144 this.setDaemon(true);
145 this.owner = owner;
146 synchronized (object)
147 {
148 this.object = object;
149 increaseCounter();
150 this.start();
151 }
152 synchronized (owner)
153 {
154 try
155 {
156 this.owner.wait();
157 }
158 catch (InterruptedException exception)
159 {
160 exception = null;
161
162
163
164
165 }
166 }
167 }
168
169
170
171
172 public synchronized int getCounter()
173 {
174 return this.counter;
175 }
176
177
178
179
180 public synchronized void decreaseCounter()
181 {
182 this.counter = Math.max(0, this.counter - 1);
183 }
184
185
186
187
188 public synchronized void increaseCounter()
189 {
190 this.counter++;
191 }
192
193
194
195
196 public Thread getOwner()
197 {
198 return this.owner;
199 }
200
201
202 @Override
203 public void run()
204 {
205 try
206 {
207
208 synchronized (this.object)
209 {
210
211
212 this.owner.interrupt();
213
214
215 this.join();
216 }
217 }
218 catch (Exception exception)
219 {
220
221
222 exception = null;
223 }
224 }
225 }
226 }