@@ -33,6 +33,7 @@ Licensed to the Apache Software Foundation (ASF) under one
33
33
import java .util .Set ;
34
34
import java .util .TreeSet ;
35
35
import java .util .Vector ;
36
+ import java .util .concurrent .locks .ReentrantLock ;
36
37
37
38
/**
38
39
* A singleton class that manages the addition and removal of WikiEvent listeners to a event source, as well as the firing of events
@@ -141,6 +142,17 @@ public final class WikiEventManager {
141
142
/* Singleton instance of the WikiEventManager. */
142
143
private static WikiEventManager c_instance ;
143
144
145
+ /**
146
+ * A lock used to ensure thread safety when accessing shared resources.
147
+ * This lock provides more flexibility and capabilities than the intrinsic locking mechanism,
148
+ * such as the ability to attempt to acquire a lock with a timeout, or to interrupt a thread
149
+ * waiting to acquire a lock.
150
+ *
151
+ * @see java.util.concurrent.locks.ReentrantLock
152
+ */
153
+ private static final ReentrantLock lock = new ReentrantLock ();
154
+
155
+
144
156
/** Constructor for a WikiEventManager. */
145
157
private WikiEventManager () {
146
158
c_instance = this ;
@@ -154,10 +166,15 @@ private WikiEventManager() {
154
166
* @return A shared instance of the WikiEventManager
155
167
*/
156
168
public static WikiEventManager getInstance () {
157
- if ( c_instance == null ) {
158
- synchronized ( WikiEventManager .class ) {
159
- return new WikiEventManager ();
160
- // start up any post-instantiation services here
169
+ if (c_instance == null ) {
170
+ lock .lock ();
171
+ try {
172
+ if (c_instance == null ) {
173
+ c_instance = new WikiEventManager ();
174
+ // start up any post-instantiation services here
175
+ }
176
+ } finally {
177
+ lock .unlock ();
161
178
}
162
179
}
163
180
return c_instance ;
@@ -242,7 +259,8 @@ public static boolean removeWikiEventListener( final WikiEventListener listener
242
259
// get the Map.entry object for the entire Map, then check match on entry (listener)
243
260
final WikiEventManager mgr = getInstance ();
244
261
final Map < Object , WikiEventDelegate > sources = Collections .synchronizedMap ( mgr .getDelegates () );
245
- synchronized ( sources ) {
262
+ lock .lock ();
263
+ try {
246
264
// get an iterator over the Map.Enty objects in the map
247
265
for ( final Map .Entry < Object , WikiEventDelegate > entry : sources .entrySet () ) {
248
266
// the entry value is the delegate
@@ -253,16 +271,24 @@ public static boolean removeWikiEventListener( final WikiEventListener listener
253
271
removed = true ; // was removed
254
272
}
255
273
}
274
+ } finally {
275
+ lock .unlock ();
256
276
}
257
277
return removed ;
258
278
}
259
279
260
280
private void removeDelegates () {
261
- synchronized ( m_delegates ) {
281
+ lock .lock ();
282
+ try {
262
283
m_delegates .clear ();
284
+ } finally {
285
+ lock .unlock ();
263
286
}
264
- synchronized ( m_preloadCache ) {
287
+ lock .lock ();
288
+ try {
265
289
m_preloadCache .clear ();
290
+ } finally {
291
+ lock .unlock ();
266
292
}
267
293
}
268
294
@@ -315,7 +341,8 @@ private Map< Object, WikiEventDelegate > getDelegates() {
315
341
* @return the WikiEventDelegate.
316
342
*/
317
343
private WikiEventDelegate getDelegateFor ( final Object client ) {
318
- synchronized ( m_delegates ) {
344
+ lock .lock ();
345
+ try {
319
346
if ( client == null || client instanceof Class ) { // then preload the cache
320
347
final WikiEventDelegate delegate = new WikiEventDelegate ( client );
321
348
m_preloadCache .add ( delegate );
@@ -342,6 +369,8 @@ private WikiEventDelegate getDelegateFor( final Object client ) {
342
369
m_delegates .put ( client , delegate );
343
370
}
344
371
return delegate ;
372
+ } finally {
373
+ lock .unlock ();
345
374
}
346
375
}
347
376
@@ -386,7 +415,8 @@ private static final class WikiEventDelegate {
386
415
* @throws java.lang.UnsupportedOperationException if any attempt is made to modify the Set
387
416
*/
388
417
public Set < WikiEventListener > getWikiEventListeners () {
389
- synchronized ( m_listenerList ) {
418
+ lock .lock ();
419
+ try {
390
420
final TreeSet < WikiEventListener > set = new TreeSet <>( new WikiEventListenerComparator () );
391
421
for ( final WeakReference < WikiEventListener > wikiEventListenerWeakReference : m_listenerList ) {
392
422
final WikiEventListener l = wikiEventListenerWeakReference .get ();
@@ -396,6 +426,8 @@ public Set< WikiEventListener > getWikiEventListeners() {
396
426
}
397
427
398
428
return Collections .unmodifiableSet ( set );
429
+ } finally {
430
+ lock .unlock ();
399
431
}
400
432
}
401
433
@@ -406,13 +438,16 @@ public Set< WikiEventListener > getWikiEventListeners() {
406
438
* @return true if the listener was added (i.e., it was not already in the list and was added)
407
439
*/
408
440
public boolean addWikiEventListener ( final WikiEventListener listener ) {
409
- synchronized ( m_listenerList ) {
441
+ lock .lock ();
442
+ try {
410
443
final boolean listenerAlreadyContained = m_listenerList .stream ()
411
444
.map ( WeakReference ::get )
412
445
.anyMatch ( ref -> ref == listener );
413
446
if ( !listenerAlreadyContained ) {
414
447
return m_listenerList .add ( new WeakReference <>( listener ) );
415
448
}
449
+ } finally {
450
+ lock .unlock ();
416
451
}
417
452
return false ;
418
453
}
@@ -424,14 +459,17 @@ public boolean addWikiEventListener( final WikiEventListener listener ) {
424
459
* @return true if the listener was removed (i.e., it was actually in the list and was removed)
425
460
*/
426
461
public boolean removeWikiEventListener ( final WikiEventListener listener ) {
427
- synchronized ( m_listenerList ) {
462
+ lock .lock ();
463
+ try {
428
464
for ( final Iterator < WeakReference < WikiEventListener > > i = m_listenerList .iterator (); i .hasNext (); ) {
429
465
final WikiEventListener l = i .next ().get ();
430
466
if ( l == listener ) {
431
467
i .remove ();
432
468
return true ;
433
469
}
434
470
}
471
+ } finally {
472
+ lock .unlock ();
435
473
}
436
474
437
475
return false ;
@@ -441,8 +479,11 @@ public boolean removeWikiEventListener( final WikiEventListener listener ) {
441
479
* Returns true if there are one or more listeners registered with this instance.
442
480
*/
443
481
public boolean isListening () {
444
- synchronized ( m_listenerList ) {
482
+ lock .lock ();
483
+ try {
445
484
return !m_listenerList .isEmpty ();
485
+ } finally {
486
+ lock .unlock ();
446
487
}
447
488
}
448
489
@@ -452,7 +493,8 @@ public boolean isListening() {
452
493
public void fireEvent ( final WikiEvent event ) {
453
494
boolean needsCleanup = false ;
454
495
try {
455
- synchronized ( m_listenerList ) {
496
+ lock .lock ();
497
+ try {
456
498
for ( final WeakReference < WikiEventListener > wikiEventListenerWeakReference : m_listenerList ) {
457
499
final WikiEventListener listener = wikiEventListenerWeakReference .get ();
458
500
if ( listener != null ) {
@@ -472,6 +514,8 @@ public void fireEvent( final WikiEvent event ) {
472
514
}
473
515
}
474
516
517
+ } finally {
518
+ lock .unlock ();
475
519
}
476
520
} catch ( final ConcurrentModificationException e ) {
477
521
// We don't die, we just don't do notifications in that case.
0 commit comments