PageRenderTime 106ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/dumbhippo/branches/production-replaced-2007-06-29/server/src/com/dumbhippo/ThreadUtils.java

https://gitlab.com/manoj-makkuboy/magnetism
Java | 235 lines | 172 code | 23 blank | 40 comment | 18 complexity | a7d1298a007dc297e26203858e4396d8 MD5 | raw file
  1. package com.dumbhippo;
  2. import java.lang.Thread.UncaughtExceptionHandler;
  3. import java.util.Collection;
  4. import java.util.List;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;
  10. import java.util.concurrent.ThreadFactory;
  11. import java.util.concurrent.TimeUnit;
  12. import org.slf4j.Logger;
  13. public class ThreadUtils {
  14. @SuppressWarnings("unused")
  15. static private final Logger logger = GlobalSetup.getLogger(ThreadUtils.class);
  16. static private int nextGlobalThreadId = 0;
  17. static private UncaughtExceptionHandler exceptionHandler = new EmergencyExceptionHandler();
  18. // note that there's also a Thread.setDefaultUncaughtExceptionHandler which sets the
  19. // global handler for all threads, but since our class will get unloaded without
  20. // exiting the jvm, setting that would be evil.
  21. // Something to be careful of is that if you do ExecutorService.submit(), it returns
  22. // a future and any exception from your runnable is set on the future as an ExecutionException,
  23. // rather than thrown out to the thread's root run(). This means that you need to
  24. // actually call get() on the Future so you get that exception. If you don't want the
  25. // future, be sure you use ExecutorService.execute(), not submit().
  26. static private class EmergencyExceptionHandler implements UncaughtExceptionHandler {
  27. @SuppressWarnings({"unused","hiding"})
  28. static private final Logger logger = GlobalSetup.getLogger(EmergencyExceptionHandler.class);
  29. public void uncaughtException(Thread thread, Throwable throwable) {
  30. logger.error("Uncaught exception terminated thread {}: {}", thread.getName(),
  31. ExceptionUtils.getRootCause(throwable).getMessage());
  32. logger.error("Exception killing thread", throwable);
  33. }
  34. }
  35. public static void shutdownAndAwaitTermination(ExecutorService service) {
  36. service.shutdown();
  37. try {
  38. service.awaitTermination(60, TimeUnit.SECONDS);
  39. } catch (InterruptedException e) {
  40. logger.error("Timed out while waiting to shut down executor service");
  41. }
  42. }
  43. /**
  44. * Like Executors.newCachedThreadPool, but you can specify the name of
  45. * the threads that will be created and the threads are daemon threads.
  46. *
  47. * @param baseName identifier of the thread pool. The threads in the
  48. * thread pool will be named "[baseName] 1", "[baseName] 2", and
  49. * so forth.
  50. * @return a newly created ExecutorService. You should call shutdown()
  51. * on this service when you are finished using it.
  52. */
  53. public static ExecutorService newCachedThreadPool(final String baseName) {
  54. return Executors.newCachedThreadPool(new ThreadFactory() {
  55. private int nextThreadId = 0;
  56. public synchronized Thread newThread(Runnable r) {
  57. Thread t = new Thread(r);
  58. t.setDaemon(true);
  59. t.setName(baseName + " " + nextThreadId);
  60. nextThreadId += 1;
  61. t.setUncaughtExceptionHandler(exceptionHandler);
  62. return t;
  63. }
  64. });
  65. }
  66. /**
  67. * Like Executors.newFixedThreadPool, but you can specify the name of
  68. * the thread that will be created and the threads are daemon threads.
  69. */
  70. public static ExecutorService newFixedThreadPool(final String baseName, int numThreads) {
  71. return Executors.newFixedThreadPool(numThreads, new ThreadFactory() {
  72. private int nextThreadId = 0;
  73. public synchronized Thread newThread(Runnable r) {
  74. Thread t = new Thread(r);
  75. t.setDaemon(true);
  76. t.setName(baseName + " " + nextThreadId);
  77. nextThreadId += 1;
  78. t.setUncaughtExceptionHandler(exceptionHandler);
  79. return t;
  80. }
  81. });
  82. }
  83. /**
  84. * Like Executors.newSingleThreadExecutor, but you can specify the name of
  85. * the thread that will be created and the threads are daemon threads.
  86. *
  87. * @param name name of the thread
  88. * @return a newly created ExecutorService. You should call shutdown()
  89. * on this service when you are finished using it.
  90. */
  91. public static ExecutorService newSingleThreadExecutor(final String name) {
  92. return Executors.newSingleThreadExecutor(new ThreadFactory() {
  93. public synchronized Thread newThread(Runnable r) {
  94. Thread t = new Thread(r);
  95. t.setDaemon(true);
  96. t.setName(name);
  97. t.setUncaughtExceptionHandler(exceptionHandler);
  98. return t;
  99. }
  100. });
  101. }
  102. public interface DaemonRunnable {
  103. public void run() throws InterruptedException;
  104. }
  105. public static Thread newDaemonThread(String name, final DaemonRunnable r) {
  106. Runnable restartingRunnable = new Runnable() {
  107. private static final long RESTART_DELAY_MS = 60 * 1000;
  108. public void run() {
  109. try {
  110. while (true) {
  111. try {
  112. r.run();
  113. break;
  114. } catch (InterruptedException e) {
  115. throw e;
  116. } catch (RuntimeException e) {
  117. logger.error("Caught unexpected exception in daemon thread, will restart in "
  118. + RESTART_DELAY_MS, e);
  119. Thread.sleep(RESTART_DELAY_MS);
  120. }
  121. }
  122. } catch (InterruptedException e) {
  123. }
  124. }
  125. };
  126. Thread t = new Thread(restartingRunnable);
  127. t.setDaemon(true);
  128. synchronized (ThreadUtils.class) {
  129. t.setName(name + " " + nextGlobalThreadId);
  130. nextGlobalThreadId += 1;
  131. }
  132. t.setUncaughtExceptionHandler(exceptionHandler);
  133. return t;
  134. }
  135. private static void logException(Exception e, boolean fullLog) {
  136. if (e instanceof InterruptedException) {
  137. if (!fullLog)
  138. logger.warn("future interrupted {}: {}", e.getClass().getName(), e.getMessage());
  139. else
  140. logger.warn("future interrupted", e);
  141. } else if (e instanceof ExecutionException) {
  142. if (!fullLog)
  143. logger.warn("future threw execution exception {}: {}", e.getClass().getName(), e.getMessage());
  144. else
  145. logger.warn("future threw execution exception", e);
  146. Throwable cause = e.getCause();
  147. if (cause != null && cause != e) {
  148. logger.warn("cause of execution exception was {}: {}", cause.getClass().getName(), cause.getMessage());
  149. }
  150. Throwable root = ExceptionUtils.getRootCause(e);
  151. if (root != null && root != e && root != cause) {
  152. logger.warn("root cause of execution exception was {}: {}", root.getClass().getName(), root.getMessage());
  153. }
  154. } else {
  155. if (!fullLog)
  156. logger.warn("future got unexpected exception {}: {}", e.getClass().getName(), e.getMessage());
  157. else
  158. logger.warn("future got unexpected exception", e);
  159. }
  160. }
  161. public static <T> T getFutureResult(Future<T> future) {
  162. try {
  163. return future.get();
  164. } catch (InterruptedException e) {
  165. logException(e, false);
  166. throw new RuntimeException(e);
  167. } catch (ExecutionException e) {
  168. logException(e, false);
  169. throw new RuntimeException(e);
  170. }
  171. }
  172. public static <T> T getFutureResultNullOnException(Future<T> future) {
  173. try {
  174. return future.get();
  175. } catch (InterruptedException e) {
  176. logException(e, true);
  177. return null;
  178. } catch (ExecutionException e) {
  179. logException(e, true);
  180. return null;
  181. }
  182. }
  183. // the Class should be Class<T> not Class<? extends T> because the caller won't know a subclass to pass in anyhow,
  184. // the "T" superclass should always be passed in
  185. public static <T> List<? extends T> getFutureResultEmptyListOnException(Future<List<? extends T>> future, Class<T> klass) {
  186. try {
  187. return future.get();
  188. } catch (InterruptedException e) {
  189. logException(e, true);
  190. return TypeUtils.emptyList(klass);
  191. } catch (ExecutionException e) {
  192. logException(e, true);
  193. return TypeUtils.emptyList(klass);
  194. }
  195. }
  196. /** Workaround for ExecutorService.invokeAll having the wrong signature - it doesn't allow a set of subclasses of callable, only
  197. * a set of callable. We think this is a bug in the declared signature, not a real limitation of the invokeAll() implementation.
  198. * So we break type safety here and force invokeAll to take a set of any subclass of Callable
  199. */
  200. @SuppressWarnings("unchecked")
  201. public static <T> List<Future<T>> invokeAll(ExecutorService executor, Collection<? extends Callable<T>> tasks) throws InterruptedException {
  202. return executor.invokeAll((Collection) tasks);
  203. }
  204. /** Workaround for ExecutorService.invokeAll having the wrong signature - it doesn't allow a set of subclasses of callable, only
  205. * a set of callable. We think this is a bug in the declared signature, not a real limitation of the invokeAll() implementation.
  206. * So we break type safety here and force invokeAll to take a set of any subclass of Callable
  207. */
  208. @SuppressWarnings("unchecked")
  209. public static <T> List<Future<T>> invokeAll(ExecutorService executor, Collection<? extends Callable<T>> tasks, long timeout, TimeUnit units) throws InterruptedException {
  210. return executor.invokeAll((Collection) tasks, timeout, units);
  211. }
  212. }