]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java
Allow ExecutorWorker thread pool shutdown
[simantics/platform.git] / bundles / org.simantics.utils.thread / src / org / simantics / utils / threads / ExecutorWorker.java
index 63cacd9895bd6b8f8b16fdfff4bc085f5a3e9e95..698d99e97a036fa8305761132ebb60162b4fefbb 100644 (file)
@@ -1,65 +1,78 @@
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-/*\r
- *\r
- * @author Toni Kalajainen\r
- */\r
-package org.simantics.utils.threads;\r
-\r
-import java.util.concurrent.Callable;\r
-import java.util.concurrent.ScheduledFuture;\r
-import java.util.concurrent.ScheduledThreadPoolExecutor;\r
-import java.util.concurrent.TimeUnit;\r
-\r
-\r
-public class ExecutorWorker {\r
-       \r
-       private static ExecutorWorker instance;\r
-       \r
-       static class DelayedExecution implements Comparable<DelayedExecution> {\r
-               Executable executable;\r
-               long executionTime;\r
-               @Override\r
-               public int compareTo(DelayedExecution o) {\r
-                       if (o.executionTime<executionTime) return -1;\r
-                       if (o.executionTime>executionTime) return 1;\r
-                       return 0;\r
-               }\r
-       }\r
-\r
-       public static ExecutorWorker getInstance()\r
-       {\r
-               if (instance == null)\r
-                       instance = new ExecutorWorker();\r
-               return instance;\r
-       }\r
-       \r
-       ExecutorWorker() {              \r
-       }       \r
-\r
-       ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);\r
-       \r
-       public synchronized ScheduledFuture<Object> timerExec(final Executable executable, int delay)\r
-       {\r
-               Callable<Object> c = new Callable<Object>() {\r
-                       @Override\r
-                       public Object call() throws Exception {\r
-                // FIXME: executable.runnable gets called twice!\r
-                               ThreadUtils.asyncExec(executable.threadAccess, executable.runnable);\r
-                               //executable.runnable.run();\r
-                               return null;\r
-                       }\r
-               };              \r
-               return pool.schedule(c, delay, TimeUnit.MILLISECONDS);\r
-       }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - added shutdown facilities
+ *******************************************************************************/
+
+package org.simantics.utils.threads;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Toni Kalajainen
+ * @author Tuukka Lehtonen
+ */
+public class ExecutorWorker {
+
+       private static volatile ExecutorWorker instance;
+
+       public static ExecutorWorker getInstance() {
+               if (instance == null) {
+                       synchronized (ExecutorWorker.class) {
+                               if (instance == null)
+                                       instance = new ExecutorWorker();
+                       }
+               }
+               return instance;
+       }
+
+       private ExecutorWorker() {}
+
+       private final AtomicInteger counter = new AtomicInteger(0);
+       private final ThreadGroup threadGroup = new ThreadGroup("ExecutorWorker-Group");
+       private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1, r -> {
+               Thread t = new Thread(threadGroup, r, "ExecutorWorker-" + (counter.incrementAndGet()));
+               if (!t.isDaemon())
+                       t.setDaemon(true);
+               if (t.getPriority() != Thread.NORM_PRIORITY)
+                       t.setPriority(Thread.NORM_PRIORITY);
+               return t;
+       });
+
+       public synchronized ScheduledFuture<Object> timerExec(final Executable executable, int delay)
+       {
+               Callable<Object> c = () -> {
+                       ThreadUtils.asyncExec(executable.threadAccess, executable.runnable);
+                       return null;
+               };
+               return pool.schedule(c, delay, TimeUnit.MILLISECONDS);
+       }
+
+       private void shutdownThis() {
+               ScheduledThreadPoolExecutor e = pool;
+               if (e != null) {
+                       pool = null;
+                       ThreadUtils.shutdownAndAwaitTermination(e, 1000);
+               }
+       }
+
+       public static synchronized void shutdown() {
+               ExecutorWorker i = instance;
+               if (i != null) {
+                       instance = null;
+                       i.shutdownThis();
+               }
+       }
+
+}