From df9d54067bc99d1ead12b7d369be0d467d574837 Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Wed, 20 Jun 2018 11:07:58 +0300 Subject: [PATCH] Allow ExecutorWorker thread pool shutdown 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 (cherry picked from commit 951846b17c8c02759b7a319b0f2952cafacb8bea) --- .../utils/threads/ExecutorWorker.java | 87 +++++++++++-------- .../simantics/utils/threads/ThreadUtils.java | 2 +- .../internal/SimanticsWorkbenchAdvisor.java | 2 + 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java index e63b304e9..698d99e97 100644 --- a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java +++ b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ExecutorWorker.java @@ -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 { - Executable executable; - long executionTime; - @Override - public int compareTo(DelayedExecution o) { - if (o.executionTimeexecutionTime) 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 timerExec(final Executable executable, int delay) { - Callable c = new Callable() { - @Override - public Object call() throws Exception { - // FIXME: executable.runnable gets called twice! - ThreadUtils.asyncExec(executable.threadAccess, executable.runnable); - //executable.runnable.run(); - return null; - } - }; + Callable 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(); + } + } + } diff --git a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ThreadUtils.java b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ThreadUtils.java index e9a6fa4e3..3b71babe2 100644 --- a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ThreadUtils.java +++ b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/ThreadUtils.java @@ -878,7 +878,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 { diff --git a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java index bce220c9c..39b797ba4 100644 --- a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java +++ b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java @@ -105,6 +105,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; @@ -754,6 +755,7 @@ public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor { progress.subTask("Thread pools"); ThreadUtils.shutdown(); + ExecutorWorker.shutdown(); progress.worked(5); progress.subTask("Clear index status"); -- 2.47.1