mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-21 19:50:01 +00:00
using new ThreadPoolUtil to size and use and, where necessary, create thread pool executors so we reduce the amount of runnable threads
Change-Id: I56a9f68aca7b28dc28fbb096f6bfb6cb9dce35a9
This commit is contained in:
1 parent
687f57caa6
commit
852f114d84
11 files changed
+105
-68
No files matched your search
@@ -13,8 +13,6 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -25,7 +23,6 @@ import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
import com.sap.sse.util.SmartFutureCache.UpdateInterval;
|
||||
import com.sap.sse.util.impl.ThreadFactoryWithPriority;
|
||||
|
||||
/**
|
||||
* A cache for which a background update can be triggered. Readers can decide whether they want to wait for any ongoing
|
||||
@@ -87,23 +84,13 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
|
||||
|
||||
private final Map<K, V> cache;
|
||||
|
||||
/**
|
||||
* When many updates are triggered in a short period of time by a single thread, ensure that the single thread
|
||||
* providing the updates is not outperformed by all the re-calculations happening here. Leave at least one
|
||||
* core to other things, but by using at least three threads ensure that no simplistic deadlocks may occur.
|
||||
*/
|
||||
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/2, 3);
|
||||
|
||||
/**
|
||||
* Note that this needs to have more than one thread because there may be calculations used for cache updates that
|
||||
* need to wait for other cache updates to finish. If those were all to be handled by a single thread, deadlocks
|
||||
* would occur. Remember that there may still be single-core machines, so the factor with which
|
||||
* <code>availableProcessors</code> is multiplied needs to be greater than one at least.
|
||||
*/
|
||||
private final static Executor recalculator = new ThreadPoolExecutor(/* corePoolSize */ THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */ THREAD_POOL_SIZE,
|
||||
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||
/* workQueue */ new LinkedBlockingQueue<Runnable>(), new ThreadFactoryWithPriority(Thread.NORM_PRIORITY-1, /* daemon */ true));
|
||||
private final static Executor recalculator = ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor();
|
||||
|
||||
private final CacheUpdater<K, V, U> cacheUpdateComputer;
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.sap.sse.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.util.impl.ThreadPoolUtilImpl;
|
||||
|
||||
public interface ThreadPoolUtil {
|
||||
ThreadPoolUtil INSTANCE = new ThreadPoolUtilImpl();
|
||||
|
||||
/**
|
||||
* Returns a central, default thread pool executor that can be used to schedule background tasks. Using this
|
||||
* centralized copy ensures that when several application modules require such an executor they get a single one
|
||||
* whose dimensions are chosen such that it does not outperform other system-critical tasks such as garbage
|
||||
* collection and JITting.
|
||||
* <p>
|
||||
*
|
||||
* The executor will have slightly less than {@link Thread#NORM_PRIORITY} as its priority, and its threads will all
|
||||
* be {@link Thread#setDaemon daemon threads}. The task queue is limited by {@link Integer#MAX_VALUE}, so is
|
||||
* virtually unbounded, and therefore no specific rejection handler is configured.
|
||||
* <p>
|
||||
*
|
||||
* The thread pool uses constant size, so the core size equals the maximum size, and threads will not be terminated
|
||||
* once created. Its size is calculated using {@link #getReasonableThreadPoolSize()}.
|
||||
*/
|
||||
ExecutorService getDefaultBackgroundTaskThreadPoolExecutor();
|
||||
|
||||
/**
|
||||
* Returns a new thread pool executor that can be used to schedule background tasks. Normally, clients should use
|
||||
* {@link #getDefaultBackgroundTaskThreadPoolExecutor()} instead. However, under certain rare circumstances it may
|
||||
* be necessary or advisable to create a separate thread pool, e.g., when the computations of tasks submitted to the
|
||||
* default thread pool depend on the results of other tasks. Those other tasks then must not be submitted to the same
|
||||
* executor as deadlocks may occur.<p>
|
||||
*
|
||||
* The same configuration as for {@link #getDefaultBackgroundTaskThreadPoolExecutor()} is used.
|
||||
*/
|
||||
ExecutorService createBackgroundTaskThreadPoolExecutor();
|
||||
|
||||
/**
|
||||
* In case an application module really requires its own thread pool instead of
|
||||
* using {@link #getBackgroundTaskThreadPool}, it should size the thread pool
|
||||
* using the value returned by this method. The number returned will scale with
|
||||
* the number of {@link Runtime#availableProcessors() CPUs available} and will
|
||||
* try to leave some room for system threads such as the garbage collector and
|
||||
* JITter.
|
||||
*/
|
||||
int getReasonableThreadPoolSize();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.sap.sse.util.impl;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.sap.sse.util.ThreadPoolUtil;
|
||||
|
||||
public class ThreadPoolUtilImpl implements ThreadPoolUtil {
|
||||
private static final int REASONABLE_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/2, 3);
|
||||
|
||||
private final ExecutorService defaultBackgroundTaskThreadPoolExecutor;
|
||||
|
||||
public ThreadPoolUtilImpl() {
|
||||
defaultBackgroundTaskThreadPoolExecutor = new ThreadPoolExecutor(/* corePoolSize */ REASONABLE_THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */ REASONABLE_THREAD_POOL_SIZE,
|
||||
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||
/* workQueue */ new LinkedBlockingQueue<Runnable>(), new ThreadFactoryWithPriority(Thread.NORM_PRIORITY-1, /* daemon */ true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService getDefaultBackgroundTaskThreadPoolExecutor() {
|
||||
return defaultBackgroundTaskThreadPoolExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService createBackgroundTaskThreadPoolExecutor() {
|
||||
return new ThreadPoolExecutor(/* corePoolSize */ REASONABLE_THREAD_POOL_SIZE,
|
||||
/* maximumPoolSize */ REASONABLE_THREAD_POOL_SIZE,
|
||||
/* keepAliveTime */ 60, TimeUnit.SECONDS,
|
||||
/* workQueue */ new LinkedBlockingQueue<Runnable>(), new ThreadFactoryWithPriority(Thread.NORM_PRIORITY-1, /* daemon */ true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReasonableThreadPoolSize() {
|
||||
return REASONABLE_THREAD_POOL_SIZE;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user