All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pro.jk.ejoker.common.system.task.defaultProvider.SystemAsyncPool Maven / Gradle / Ivy

There is a newer version: 3.0.7.1
Show newest version
package pro.jk.ejoker.common.system.task.defaultProvider;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pro.jk.ejoker.common.system.extension.acrossSupport.RipenFuture;
import pro.jk.ejoker.common.system.functional.IFunction;
import pro.jk.ejoker.common.system.task.IAsyncEntrance;

public class SystemAsyncPool implements IAsyncEntrance {

	@SuppressWarnings("unused")
	private final static Logger logger = LoggerFactory.getLogger(SystemAsyncPool.class);
	
	private final static String threadNamePrefix = "ejoker-worker-";

	private final ExecutorService defaultThreadPool;
	
	public SystemAsyncPool(int threadPoolSize) {
		this(threadPoolSize, false);
	}

	public SystemAsyncPool(int threadPoolSize, boolean prestartAllThread) {
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
				threadPoolSize,
				threadPoolSize,
				0l,
				TimeUnit.MILLISECONDS,
				new LinkedBlockingQueue<>(),
				new ThreadFactory() {
					private final AtomicLong threadIndex = new AtomicLong(0);
					private final String threadNamePrefix;
					private final boolean daemon;

					@Override
					public Thread newThread(Runnable r) {
						Thread thread = new Thread(r, threadNamePrefix + this.threadIndex.incrementAndGet());
						thread.setDaemon(daemon);
						return thread;
					}

					{
						// constructor
						this.threadNamePrefix = SystemAsyncPool.threadNamePrefix;
						this.daemon = false;
					}
				},
				new ThreadPoolExecutor.CallerRunsPolicy());
		if (prestartAllThread)
			threadPoolExecutor.prestartAllCoreThreads();
		defaultThreadPool = threadPoolExecutor;

	}

	@Override
	public  Future execute(IFunction asyncTaskThread,
			boolean reuse) {
		if (
				reuse
				&& Thread.currentThread().getName().startsWith(SystemAsyncPool.threadNamePrefix)
				) {
			// @important 1. 如果当前提交线程本来就是线程池中的线程,则由当前线程直接执行
			// @important 2. 如果当前线程池的任务队列中有等待的任务,则由当前线程直接执行(可以视为线程池满载了,在提交任务前直接执行CallerRunsPolicy策略)
			RipenFuture future = new RipenFuture<>();
			try {
				future.trySetResult(asyncTaskThread.trigger());
			} catch (Exception e) {
				future.trySetException(e);
			}
			return future;
		}

		// @important 建立新线程存在线程上限和大量的上下文切换成本,极易发生OutOfMemory。
		// @important 或者使用cachedThreadPool??

		// @important 使用线程池模式的话,正常的情况还好,但是有一个棘手的问题,
		// @important 在整个系统中某一个有超过系统空闲线程(或这个数量级附近时),
		// @important 假设这些存量线程都在开新任务并异步等待结果的话,
		// @important 系统会处于死锁和饿死状态中(对旧线程是死锁,对新任务则是饿死),
		// @important 旧的任务将永远等不到他们的结果,新的任务却没有任何新线程来处理。
		// @important 不治本的解决方法:
		// @important 	1. 基于框架的幂等性,我们可以重启程序,重新接受指令。
		// @important 	2. 采用线程池占满补偿方案:
		// @important 		采用游离线程处理等待中的任务,且不接受超过n毫秒的任务,超时即杀死,并向提交此任务的线程返回异常。
		// @important 		* 可能长时间存在游离线程一直被杀死,且提交线程不断重试的情况。
		// @important 	3. 不使用异步任务,直接当前线程执行。
		return defaultThreadPool.submit(asyncTaskThread::trigger);

		// @important 根治的解决方法使用coroutine方案,目前考虑使用 Quasar 方案
	}

	public void shutdown() {
		defaultThreadPool.shutdown();
	}

	@Override
	public  Future execute(IFunction asyncTaskThread) {
		return execute(asyncTaskThread, true);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy