1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.core.util;
17
18 import java.util.concurrent.Semaphore;
19
20 import org.apache.log4j.Logger;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class ConcurrencyDetector {
45
46
47 private ThreadLocal<Boolean> ACQUIRED_SEMAPHORE = new ThreadLocal<Boolean>() {
48 @Override
49 protected Boolean initialValue() {
50 return Boolean.FALSE;
51 }
52 };
53 private final Logger log;
54 private final String name;
55 private final boolean trackStacktraces;
56 private final Semaphore semaphore = new Semaphore(1);
57
58 private Throwable entryPoint;
59
60 public ConcurrencyDetector() {
61 this(ConcurrencyDetector.class.getName());
62 }
63
64 public ConcurrencyDetector(String name) {
65 this(name, true);
66 }
67
68 public ConcurrencyDetector(String name, boolean trackStacktraces) {
69 this.log = Logger.getLogger(name);
70 this.name = name;
71 this.trackStacktraces = trackStacktraces;
72 }
73
74 public synchronized boolean enter() {
75 boolean acquired = semaphore.tryAcquire();
76 ACQUIRED_SEMAPHORE.set(Boolean.valueOf(acquired));
77 if (!acquired) {
78 onConcurrencyDetected();
79 } else {
80 if (trackStacktraces) {
81 entryPoint = new Throwable("Initial entry");
82 }
83 }
84 return acquired;
85 }
86
87 public synchronized void exit() {
88 if (ACQUIRED_SEMAPHORE.get()) {
89 if (trackStacktraces) {
90 entryPoint = null;
91 }
92 semaphore.release();
93 }
94 }
95
96
97
98
99
100 protected void onConcurrencyDetected() {
101 log.error("Concurrency was detected");
102 if (trackStacktraces) {
103 entryPoint.printStackTrace();
104 new Throwable("Second entry").printStackTrace();
105 }
106 }
107 }