Allow ExecutorWorker thread pool shutdown 65/1865/2
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 20 Jun 2018 08:07:58 +0000 (11:07 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 20 Jun 2018 08:18:05 +0000 (08:18 +0000)
Also made the pool spawn daemon threads to allow shutdown regardless of
whether the pool is shut down or not.

gitlab #29

Change-Id: I680e15407c0fd0586070a212d291efd44dc28f5d

bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ThreadUtils.java
bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java

index e63b304e9e27c7df7ca58f2efbea9ac7daa3a2ee..698d99e97a036fa8305761132ebb60162b4fefbb 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * 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
@@ -8,58 +8,71 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - added shutdown facilities
  *******************************************************************************/
-/*
- *
- * @author Toni Kalajainen
- */
+
 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 ExecutorWorker instance;
-       
-       static class DelayedExecution implements Comparable<DelayedExecution> {
-               Executable executable;
-               long executionTime;
-               @Override
-               public int compareTo(DelayedExecution o) {
-                       if (o.executionTime<executionTime) return -1;
-                       if (o.executionTime>executionTime) return 1;
-                       return 0;
-               }
-       }
 
-       public static ExecutorWorker getInstance()
-       {
-               if (instance == null)
-                       instance = new ExecutorWorker();
+       private static volatile ExecutorWorker instance;
+
+       public static ExecutorWorker getInstance() {
+               if (instance == null) {
+                       synchronized (ExecutorWorker.class) {
+                               if (instance == null)
+                                       instance = new ExecutorWorker();
+                       }
+               }
                return instance;
        }
-       
-       ExecutorWorker() {              
-       }       
 
-       ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
-       
+       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 = new Callable<Object>() {
-                       @Override
-                       public Object call() throws Exception {
-                // FIXME: executable.runnable gets called twice!
-                               ThreadUtils.asyncExec(executable.threadAccess, executable.runnable);
-                               //executable.runnable.run();
-                               return null;
-                       }
-               };              
+               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();
+               }
+       }
+
 }
index cd8d6027e4d7c54b56eaa56a3ef39b24ea4adcae..15e818416bbd0d044ddcd05c115f21019409b88b 100644 (file)
@@ -882,7 +882,7 @@ public class ThreadUtils {
      * 
      * @param pool {@link ExecutorService} to shut down
      */
-    private static void shutdownAndAwaitTermination(ExecutorService pool, long timeoutMs) {
+    static void shutdownAndAwaitTermination(ExecutorService pool, long timeoutMs) {
         //long t = System.currentTimeMillis();
         pool.shutdown(); // Disable new tasks from being submitted
         try {
index 591c7fd423d2bdb1ca14a7daf76dfa8cabcb68f0..29ee52e61be601ec5583c8ad27f406f4044ff76f 100644 (file)
@@ -106,6 +106,7 @@ import org.simantics.ui.jobs.SessionGarbageCollectorJob;
 import org.simantics.ui.workbench.PerspectiveBarsActivator;
 import org.simantics.ui.workbench.PerspectiveContextActivator;
 import org.simantics.utils.logging.TimeLogger;
+import org.simantics.utils.threads.ExecutorWorker;
 import org.simantics.utils.threads.ThreadUtils;
 import org.simantics.utils.ui.dialogs.ShowError;
 import org.simantics.utils.ui.dialogs.ShowMessage;
@@ -749,6 +750,7 @@ public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor {
 
                 progress.subTask("Thread pools");
                 ThreadUtils.shutdown();
+                ExecutorWorker.shutdown();
                 progress.worked(5);
 
                 progress.subTask("Clear index status");