Coverage Report - net.admin4j.monitor.BlockedThreadDetector
 
Classes in this File Line Coverage Branch Coverage Complexity
BlockedThreadDetector
97%
45/46
94%
17/18
3
 
 1  
 /*
 2  
  * This software is licensed under the Apache License, Version 2.0
 3  
  * (the "License") agreement; you may not use this file except in compliance with
 4  
  * the License.  You may obtain a copy of the License at
 5  
  * 
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  * 
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 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  
  * Daemon that detects thread contention and emails an admin group.
 33  
  * @author D. Ashmore
 34  
  * @since 1.0
 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  
         /* (non-Javadoc)
 52  
      * @see java.lang.Runnable#run()
 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  
                 // Init for next time.
 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  
 }