1 /* 2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jmx.snmp.tasks; 27 28 import java.util.ArrayList; 29 import com.sun.jmx.snmp.tasks.Task; 30 import com.sun.jmx.snmp.tasks.TaskServer; 31 32 /** 33 * This class implements a {@link com.sun.jmx.snmp.tasks.TaskServer} over 34 * a thread pool. 35 * <p><b>This API is a Sun Microsystems internal API and is subject 36 * to change without notice.</b></p> 37 **/ 38 public class ThreadService implements TaskServer { 39 40 public ThreadService(int threadNumber) { 41 if (threadNumber <= 0) { 42 throw new IllegalArgumentException("The thread number should bigger than zero."); 43 } 44 45 minThreads = threadNumber; 46 threadList = new ExecutorThread[threadNumber]; 47 48 priority = Thread.currentThread().getPriority(); 49 cloader = Thread.currentThread().getContextClassLoader(); 50 51 } 52 53 // public methods 54 // -------------- 55 56 /** 57 * Submit a task to be executed. 58 * Once a task is submitted, it is guaranteed that either 59 * {@link com.sun.jmx.snmp.tasks.Task#run() task.run()} or 60 * {@link com.sun.jmx.snmp.tasks.Task#cancel() task.cancel()} will be called. 61 * This implementation of TaskServer uses a thread pool to execute 62 * the submitted tasks. 63 * @param task The task to be executed. 64 * @exception IllegalArgumentException if the submitted task is null. 65 **/ 66 public void submitTask(Task task) throws IllegalArgumentException { 67 submitTask((Runnable)task); 68 } 69 70 /** 71 * Submit a task to be executed. 72 * This implementation of TaskServer uses a thread pool to execute 73 * the submitted tasks. 74 * @param task The task to be executed. 75 * @exception IllegalArgumentException if the submitted task is null. 76 **/ 77 public void submitTask(Runnable task) throws IllegalArgumentException { 78 stateCheck(); 79 80 if (task == null) { 81 throw new IllegalArgumentException("No task specified."); 82 } 83 84 synchronized(jobList) { 85 jobList.add(jobList.size(), task); 86 87 jobList.notify(); 88 } 89 90 createThread(); 91 } 92 93 public Runnable removeTask(Runnable task) { 94 stateCheck(); 95 96 Runnable removed = null; 97 synchronized(jobList) { 98 int lg = jobList.indexOf(task); 99 if (lg >= 0) { 100 removed = jobList.remove(lg); 101 } 102 } 103 if (removed != null && removed instanceof Task) 104 ((Task) removed).cancel(); 105 return removed; 106 } 107 108 public void removeAll() { 109 stateCheck(); 110 111 final Object[] jobs; 112 synchronized(jobList) { 113 jobs = jobList.toArray(); 114 jobList.clear(); 115 } 116 final int len = jobs.length; 117 for (int i=0; i<len ; i++) { 118 final Object o = jobs[i]; 119 if (o!= null && o instanceof Task) ((Task)o).cancel(); 120 } 121 } 122 123 // to terminate 124 public void terminate() { 125 126 if (terminated == true) { 127 return; 128 } 129 130 terminated = true; 131 132 synchronized(jobList) { 133 jobList.notifyAll(); 134 } 135 136 removeAll(); 137 138 for (int i=0; i<currThreds; i++) { 139 try { 140 threadList[i].interrupt(); 141 } catch (Exception e) { 142 // TODO 143 } 144 } 145 146 threadList = null; 147 } 148 149 // private classes 150 // --------------- 151 152 // A thread used to execute jobs 153 // 154 private class ExecutorThread extends Thread { 155 public ExecutorThread() { 156 super(threadGroup, "ThreadService-"+counter++); 157 setDaemon(true); 158 159 // init 160 this.setPriority(priority); 161 this.setContextClassLoader(cloader); 162 163 idle++; 164 } 165 166 public void run() { 167 168 while(!terminated) { 169 Runnable job = null; 170 171 synchronized(jobList) { 172 if (jobList.size() > 0) { 173 job = jobList.remove(0); 174 if (jobList.size() > 0) { 175 jobList.notify(); 176 } 177 178 } else { 179 try { 180 jobList.wait(); 181 } catch (InterruptedException ie) { 182 // terminated ? 183 } finally { 184 } 185 continue; 186 } 187 } 188 if (job != null) { 189 try { 190 idle--; 191 job.run(); 192 } catch (Exception e) { 193 // TODO 194 e.printStackTrace(); 195 } finally { 196 idle++; 197 } 198 } 199 200 // re-init 201 this.setPriority(priority); 202 Thread.interrupted(); 203 this.setContextClassLoader(cloader); 204 } 205 } 206 } 207 208 // private methods 209 private void stateCheck() throws IllegalStateException { 210 if (terminated) { 211 throw new IllegalStateException("The thread service has been terminated."); 212 } 213 } 214 215 private void createThread() { 216 if (idle < 1) { 217 synchronized(threadList) { 218 if (jobList.size() > 0 && currThreds < minThreads) { 219 ExecutorThread et = new ExecutorThread(); 220 et.start(); 221 threadList[currThreds++] = et; 222 } 223 } 224 } 225 } 226 227 228 // protected or private variables 229 // ------------------------------ 230 private ArrayList<Runnable> jobList = new ArrayList<Runnable>(0); 231 232 private ExecutorThread[] threadList; 233 private int minThreads = 1; 234 private int currThreds = 0; 235 private int idle = 0; 236 237 private boolean terminated = false; 238 private int priority; 239 private ThreadGroup threadGroup = new ThreadGroup("ThreadService"); 240 private ClassLoader cloader; 241 242 private static long counter = 0; 243 244 private int addedJobs = 1; 245 private int doneJobs = 1; 246 }