1. /*
  2. * @(#)file ThreadService.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 1.8
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. *
  10. */
  11. package com.sun.jmx.snmp.tasks;
  12. import java.util.ArrayList;
  13. import com.sun.jmx.snmp.tasks.Task;
  14. import com.sun.jmx.snmp.tasks.TaskServer;
  15. /**
  16. * This class implements a {@link com.sun.jmx.snmp.tasks.TaskServer} over
  17. * a thread pool.
  18. * <p><b>This API is a Sun Microsystems internal API and is subject
  19. * to change without notice.</b></p>
  20. **/
  21. public class ThreadService implements TaskServer {
  22. public ThreadService(int threadNumber) {
  23. if (threadNumber <= 0) {
  24. throw new IllegalArgumentException("The thread number should bigger than zero.");
  25. }
  26. minThreads = threadNumber;
  27. threadList = new ExecutorThread[threadNumber];
  28. // for (int i=0; i<threadNumber; i++) {
  29. // threadList[i] = new ExecutorThread();
  30. // threadList[i].start();
  31. // }
  32. priority = Thread.currentThread().getPriority();
  33. cloader = Thread.currentThread().getContextClassLoader();
  34. //System.out.println("---jsl: ThreadService: running threads = "+threadNumber);
  35. }
  36. // public methods
  37. // --------------
  38. /**
  39. * Submit a task to be executed.
  40. * Once a task is submitted, it is guaranteed that either
  41. * {@link com.sun.jmx.snmp.tasks.Task#run() task.run()} or
  42. * {@link com.sun.jmx.snmp.tasks.Task#cancel() task.cancel()} will be called.
  43. * This implementation of TaskServer uses a thread pool to execute
  44. * the submitted tasks.
  45. * @param task The task to be executed.
  46. * @exception IllegalArgumentException if the submitted task is null.
  47. **/
  48. public void submitTask(Task task) throws IllegalArgumentException {
  49. submitTask((Runnable)task);
  50. }
  51. /**
  52. * Submit a task to be executed.
  53. * This implementation of TaskServer uses a thread pool to execute
  54. * the submitted tasks.
  55. * @param task The task to be executed.
  56. * @exception IllegalArgumentException if the submitted task is null.
  57. **/
  58. public void submitTask(Runnable task) throws IllegalArgumentException {
  59. stateCheck();
  60. if (task == null) {
  61. throw new IllegalArgumentException("No task specified.");
  62. }
  63. synchronized(jobList) {
  64. jobList.add(jobList.size(), task);
  65. //System.out.println("jsl-ThreadService: added job "+addedJobs++);
  66. jobList.notify();
  67. }
  68. createThread();
  69. }
  70. public Runnable removeTask(Runnable task) {
  71. stateCheck();
  72. Runnable removed = null;
  73. synchronized(jobList) {
  74. int lg = jobList.indexOf(task);
  75. if (lg >= 0) {
  76. removed = (Runnable)jobList.remove(lg);
  77. }
  78. }
  79. if (removed != null && removed instanceof Task)
  80. ((Task) removed).cancel();
  81. return removed;
  82. }
  83. public void removeAll() {
  84. stateCheck();
  85. final Object[] jobs;
  86. synchronized(jobList) {
  87. jobs = jobList.toArray();
  88. jobList.clear();
  89. }
  90. final int len = jobs.length;
  91. for (int i=0; i<len ; i++) {
  92. final Object o = jobs[i];
  93. if (o!= null && o instanceof Task) ((Task)o).cancel();
  94. }
  95. }
  96. // to terminate
  97. public void terminate() {
  98. if (terminated == true) {
  99. return;
  100. }
  101. terminated = true;
  102. synchronized(jobList) {
  103. jobList.notifyAll();
  104. }
  105. removeAll();
  106. for (int i=0; i<currThreds; i++) {
  107. try {
  108. threadList[i].interrupt();
  109. } catch (Exception e) {
  110. // TODO
  111. }
  112. }
  113. threadList = null;
  114. }
  115. // private classes
  116. // ---------------
  117. // A thread used to execute jobs
  118. //
  119. private class ExecutorThread extends Thread {
  120. public ExecutorThread() {
  121. super(threadGroup, "ThreadService-"+counter++);
  122. setDaemon(true);
  123. // init
  124. this.setPriority(priority);
  125. this.setContextClassLoader(cloader);
  126. idle++;
  127. }
  128. public void run() {
  129. while(!terminated) {
  130. Runnable job = null;
  131. synchronized(jobList) {
  132. if (jobList.size() > 0) {
  133. job = (Runnable)jobList.remove(0);
  134. if (jobList.size() > 0) {
  135. jobList.notify();
  136. }
  137. } else {
  138. try {
  139. jobList.wait();
  140. } catch (InterruptedException ie) {
  141. // terminated ?
  142. } finally {
  143. }
  144. continue;
  145. }
  146. }
  147. if (job != null) {
  148. try {
  149. idle--;
  150. job.run();
  151. //System.out.println("jsl-ThreadService: done job "+doneJobs++);
  152. } catch (Exception e) {
  153. // TODO
  154. e.printStackTrace();
  155. } finally {
  156. idle++;
  157. }
  158. }
  159. // re-init
  160. this.setPriority(priority);
  161. this.interrupted();
  162. this.setContextClassLoader(cloader);
  163. }
  164. }
  165. }
  166. // private methods
  167. private void stateCheck() throws IllegalStateException {
  168. if (terminated) {
  169. throw new IllegalStateException("The thread service has been terminated.");
  170. }
  171. }
  172. private void createThread() {
  173. if (idle < 1) {
  174. synchronized(threadList) {
  175. if (jobList.size() > 0 && currThreds < minThreads) {
  176. ExecutorThread et = new ExecutorThread();
  177. et.start();
  178. threadList[currThreds++] = et;
  179. //System.out.println("jsl-ThreadService: create new thread: "+currThreds);
  180. }
  181. }
  182. }
  183. }
  184. // protected or private variables
  185. // ------------------------------
  186. private ArrayList jobList = new ArrayList(0);
  187. private ExecutorThread[] threadList;
  188. private int minThreads = 1;
  189. private int currThreds = 0;
  190. private int idle = 0;
  191. private boolean terminated = false;
  192. private int priority;
  193. private ThreadGroup threadGroup = new ThreadGroup("ThreadService");
  194. private ClassLoader cloader;
  195. private static long counter = 0;
  196. private int addedJobs = 1;
  197. private int doneJobs = 1;
  198. }