1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
package net.admin4j.monitor; |
15 | |
|
16 | |
import java.lang.management.ThreadInfo; |
17 | |
import java.util.Date; |
18 | |
import java.util.HashMap; |
19 | |
import java.util.HashSet; |
20 | |
import java.util.Iterator; |
21 | |
import java.util.Map; |
22 | |
import java.util.Set; |
23 | |
|
24 | |
import net.admin4j.util.HostUtils; |
25 | |
import net.admin4j.util.notify.Notifier; |
26 | |
import net.admin4j.util.threaddumper.ThreadDumperFactory; |
27 | |
|
28 | |
import org.slf4j.Logger; |
29 | |
import org.slf4j.LoggerFactory; |
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
|
36 | |
public class BlockedThreadDetector extends Detector { |
37 | |
|
38 | |
public static final long DEFAULT_SLEEP_INTERVAL=30000; |
39 | |
|
40 | |
public static final int DEFAULT_BLOCKED_THREAD_THRESHOLD=2; |
41 | 9 | private int nbrBlockedThreadThreashold = DEFAULT_BLOCKED_THREAD_THRESHOLD; |
42 | 9 | HashSet<Long> previouslyBlockedSet = new HashSet<Long>(); |
43 | |
|
44 | 6 | private static Logger log = LoggerFactory.getLogger(BlockedThreadDetector.class); |
45 | |
|
46 | |
public BlockedThreadDetector(Notifier notifier, int nbrBlockedThreadThreashold) { |
47 | 9 | super(notifier); |
48 | 9 | this.nbrBlockedThreadThreashold = nbrBlockedThreadThreashold; |
49 | 9 | } |
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
public void run() { |
55 | 171 | this.checkThreads(); |
56 | 171 | } |
57 | |
|
58 | |
private void checkThreads() { |
59 | 171 | Set<ThreadInfo> waitingForLockSet = new HashSet<ThreadInfo>(); |
60 | 171 | Set<ThreadInfo> holdingLockSet = new HashSet<ThreadInfo>(); |
61 | 171 | Set<ThreadInfo> alsoBlockedLastIntervalSet = new HashSet<ThreadInfo>(); |
62 | |
|
63 | 171 | ThreadInfo[] tInfo = ThreadDumperFactory.getThreadDumper().dumpAllThreads(); |
64 | |
ThreadInfo lockingThread; |
65 | 171 | int lockedCount = 0; |
66 | |
|
67 | |
long lockingthreadId; |
68 | 1710 | for (ThreadInfo thread: tInfo) { |
69 | 1539 | if (Thread.State.BLOCKED.equals(thread.getThreadState())) { |
70 | 342 | lockedCount++; |
71 | |
|
72 | 342 | waitingForLockSet.add(thread); |
73 | 342 | if (this.previouslyBlockedSet.contains(thread.getThreadId())) { |
74 | 336 | alsoBlockedLastIntervalSet.add(thread); |
75 | |
} |
76 | |
|
77 | 342 | lockingthreadId = thread.getLockOwnerId(); |
78 | 342 | lockingThread = this.findThread(tInfo, lockingthreadId); |
79 | 342 | holdingLockSet.add(lockingThread); |
80 | |
|
81 | |
} |
82 | |
|
83 | |
} |
84 | 171 | if (alsoBlockedLastIntervalSet.size() >= nbrBlockedThreadThreashold) { |
85 | 168 | log.debug(lockedCount + " threads are Waiting for Locks out of " + tInfo.length + " active threads."); |
86 | 168 | this.sendBlockedThreadNotice(waitingForLockSet, holdingLockSet, alsoBlockedLastIntervalSet); |
87 | |
} |
88 | |
|
89 | |
|
90 | 171 | previouslyBlockedSet.clear(); |
91 | 171 | Iterator<ThreadInfo> threadIt = waitingForLockSet.iterator(); |
92 | 513 | while (threadIt.hasNext()) { |
93 | 342 | previouslyBlockedSet.add(threadIt.next().getThreadId()); |
94 | |
} |
95 | |
|
96 | 171 | } |
97 | |
|
98 | |
protected void sendBlockedThreadNotice(Set<ThreadInfo> waitingForLockSet, |
99 | |
Set<ThreadInfo> holdingLockSet, |
100 | |
Set<ThreadInfo> alsoBlockedLastIntervalSet) { |
101 | 177 | Map<String, Object> variableMap = new HashMap<String, Object>(); |
102 | 177 | variableMap.put("host", HostUtils.getHostName()); |
103 | 177 | variableMap.put("waitingForLockSet", waitingForLockSet); |
104 | 177 | variableMap.put("holdingLockSet", holdingLockSet); |
105 | 177 | variableMap.put("alsoBlockedLastIntervalSet", alsoBlockedLastIntervalSet); |
106 | 177 | variableMap.put("currentDatetime", new Date()); |
107 | |
|
108 | 177 | if (this.getNotifier().supportsHtml()) { |
109 | 3 | this.sendMessage(HostUtils.getHostName() + ": Blocked Threads Detected", "blockedThreadNoticeHtml.ftl", variableMap); |
110 | |
} |
111 | 174 | else if (this.getNotifier().supportsSMS()) { |
112 | 3 | this.getNotifier().notify(HostUtils.getHostName() + |
113 | |
": Blocked Threads Detected", waitingForLockSet.size() + " currently blocking other threads."); |
114 | |
} |
115 | |
else { |
116 | 171 | this.sendMessage(HostUtils.getHostName() + ": Blocked Threads Detected", "blockedThreadNoticeText.ftl", variableMap); |
117 | |
} |
118 | 177 | } |
119 | |
|
120 | |
private ThreadInfo findThread(ThreadInfo[] tInfo, long threadId) { |
121 | 1368 | for (ThreadInfo thread: tInfo) { |
122 | 1368 | if (thread.getThreadId() == threadId) { |
123 | 342 | return thread; |
124 | |
} |
125 | |
} |
126 | |
|
127 | 0 | return null; |
128 | |
} |
129 | |
|
130 | |
} |