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

com.taotao.boot.monitor.Monitor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2020-2030, Shuigedeng ([email protected] & https://blog.taotaocloud.top/).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.taotao.boot.monitor;

import com.taotao.boot.common.exception.BaseException;
import com.taotao.boot.common.model.Callable.Action1;
import com.taotao.boot.common.utils.log.LogUtils;
import com.taotao.boot.common.utils.thread.ThreadUtils;
import com.taotao.boot.core.properties.AsyncProperties;
import com.taotao.boot.core.support.Collector;
import com.taotao.boot.core.support.Ref;
import com.taotao.boot.core.support.ShutdownHooks;
import com.taotao.boot.monitor.properties.MonitorThreadPoolProperties;
import org.dromara.hutool.core.collection.CollUtil;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 自定义线程池及关键方法包装实现 装饰
 *
 * @author shuigedeng
 * @version 2021.9
 * @since 2021-09-02 20:46:36
 */
public class Monitor {

	public static final String TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY = "ttc.async.executor";
	public static final String TTC_COLLECTOR_ASYNC_EXECUTOR_HOOK = "ttc.async.executor.hook";

	public static final String TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY = "ttc.monitor.executor";
	public static final String TTC_COLLECTOR_MONITOR_EXECUTOR_HOOK = "ttc.monitor.executor.hook";

	private ThreadPoolExecutor monitorThreadPoolExecutor;
	private ThreadPoolTaskExecutor asyncThreadPoolExecutor;

	private MonitorThreadPoolProperties monitorThreadPoolProperties;
	private AsyncProperties asyncProperties;

	private Collector collector;

	public Monitor(
		Collector collector,
		AsyncProperties asyncProperties,
		MonitorThreadPoolProperties monitorThreadPoolProperties,
		ThreadPoolTaskExecutor asyncThreadPoolExecutor,
		ThreadPoolExecutor monitorThreadPoolExecutor) {

		this.collector = collector;

		// 核心线程池
		this.asyncThreadPoolExecutor = asyncThreadPoolExecutor;
		this.asyncProperties = asyncProperties;
		// 监控线程池
		this.monitorThreadPoolExecutor = monitorThreadPoolExecutor;
		this.monitorThreadPoolProperties = monitorThreadPoolProperties;

		if (Objects.nonNull(this.monitorThreadPoolExecutor)) {
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".active.count")
				.set(this.monitorThreadPoolExecutor::getActiveCount);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".core.pool.size")
				.set(this.monitorThreadPoolExecutor::getCorePoolSize);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".pool.size.largest")
				.set(this.monitorThreadPoolExecutor::getLargestPoolSize);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".pool.size.max")
				.set(this.monitorThreadPoolExecutor::getMaximumPoolSize);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".pool.size.count")
				.set(this.monitorThreadPoolExecutor::getPoolSize);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".queue.size")
				.set(() -> this.monitorThreadPoolExecutor.getQueue().size());
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".task.count")
				.set(this.monitorThreadPoolExecutor::getTaskCount);
			call(TTC_COLLECTOR_MONITOR_EXECUTOR_CALL_KEY + ".task.completed")
				.set(this.monitorThreadPoolExecutor::getCompletedTaskCount);
		}

		if (Objects.nonNull(this.asyncThreadPoolExecutor)) {
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".active.count")
				.set(this.asyncThreadPoolExecutor::getActiveCount);
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".core.pool.size")
				.set(this.asyncThreadPoolExecutor::getCorePoolSize);
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".pool.size.largest")
				.set(() ->
					this.asyncThreadPoolExecutor.getThreadPoolExecutor().getLargestPoolSize());
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".pool.size.max")
				.set(() ->
					this.asyncThreadPoolExecutor.getThreadPoolExecutor().getMaximumPoolSize());
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".pool.size.count")
				.set(this.asyncThreadPoolExecutor::getPoolSize);
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".queue.size").set(
				() -> this.asyncThreadPoolExecutor
					.getThreadPoolExecutor()
					.getQueue()
					.size());
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".task.count")
				.set(() ->
					this.asyncThreadPoolExecutor.getThreadPoolExecutor().getTaskCount());
			call(TTC_COLLECTOR_ASYNC_EXECUTOR_CALL_KEY + ".task.completed")
				.set(() ->
					this.asyncThreadPoolExecutor.getThreadPoolExecutor().getCompletedTaskCount());
		}
		ShutdownHooks.register(new ShutdownHooks.ShutdownHookHandler() {

			@Override
			public int getOrder() {
				return 1;
			}

			@Override
			public void runHook() throws Exception {
				ShutdownHooks.ShutdownHookHandler.super.runHook();
				monitorShutdown();
				asyncShutdown();
			}

			@Override
			public String description() {
				return "关闭监控现场池、关闭核心异步现场池";
			}
		});
	}

	public Collector.Call call(String key) {
		return collector.call(key);
	}

	public Collector.Hook monitorHook() {
		return collector.hook(TTC_COLLECTOR_MONITOR_EXECUTOR_HOOK);
	}

	public Collector.Hook asyncHook() {
		return collector.hook(TTC_COLLECTOR_ASYNC_EXECUTOR_HOOK);
	}

	private void monitorThreadPoolCheckHealth() {
		if (monitorThreadPoolProperties.isCheckHealth()
			&& monitorThreadPoolExecutor.getMaximumPoolSize()
			<= monitorThreadPoolExecutor.getPoolSize()
			&& !monitorThreadPoolExecutor.getQueue().isEmpty()) {
			LogUtils.warn(
				"监控线程池已满 任务开始出现排队 请修改配置 [taotao.cloud.core.threadpool.monitor.maximumPoolSize]"
					+ " 当前活动线程数: {}",
				monitorThreadPoolExecutor.getActiveCount());
		}
	}

	private void coreThreadPoolCheckHealth() {
		if (asyncProperties.isCheckHealth()
			&& asyncThreadPoolExecutor.getMaxPoolSize() <= asyncThreadPoolExecutor.getPoolSize()
			&& !asyncThreadPoolExecutor.getThreadPoolExecutor().getQueue().isEmpty()) {
			LogUtils.warn(
				"核心线程池已满 任务开始出现排队 请修改配置 [taotao.cloud.core.threadpool.async.threadPoolMaxSiz]"
					+ " 当前活动线程数: {}",
				asyncThreadPoolExecutor.getActiveCount());
		}
	}

	public  Future monitorSubmit(String taskName, Callable task) {
		monitorThreadPoolCheckHealth();

		return monitorHook().run(taskName, () -> monitorThreadPoolExecutor.submit(task));
	}

	public  Future asyncSubmit(String taskName, Callable task) {
		if (Objects.isNull(asyncThreadPoolExecutor)) {
			LogUtils.warn("核心线程池未初始化");
			return null;
		}

		coreThreadPoolCheckHealth();
		return asyncHook().run(taskName, () -> asyncThreadPoolExecutor.submit(task));
	}

	public void monitorSubmit(String taskName, Runnable task) {
		monitorThreadPoolCheckHealth();
		monitorHook().run(taskName, () -> monitorThreadPoolExecutor.submit(task));
	}

	public Future asyncSubmit(String taskName, Runnable task) {
		if (Objects.isNull(asyncThreadPoolExecutor)) {
			LogUtils.warn("核心线程池未初始化");
			return null;
		}

		coreThreadPoolCheckHealth();
		return asyncHook().run(taskName, () -> asyncThreadPoolExecutor.submit(task));
	}

	public boolean monitorIsShutdown() {
		return monitorThreadPoolExecutor.isShutdown();
	}

	public boolean coreIsShutdown() {
		if (Objects.isNull(asyncThreadPoolExecutor)) {
			LogUtils.warn("核心线程池未初始化");
			return true;
		}

		return asyncThreadPoolExecutor.getThreadPoolExecutor().isShutdown();
	}

	public void monitorShutdown() {
		ThreadUtils.shutdownThreadPool(monitorThreadPoolExecutor);
	}


	public void asyncShutdown() {
		if (Objects.nonNull(asyncThreadPoolExecutor)) {
			asyncThreadPoolExecutor.destroy();
		}
	}

	/**
	 * 任务拆分多个小任务分批并行处理,并行处理完一批再并行处理下一批。 在抛出错误的时候有问题,未修复,仅试验,不要用这个方法。
	 *
	 * @param taskName      taskName
	 * @param parallelCount parallelCount
	 * @param array         array
	 * @param action        action
	 * @since 2021-09-02 20:48:09
	 */
	public  void monitorParallelFor(String taskName, int parallelCount, List array,
		final Action1 action) {
		monitorThreadPoolCheckHealth();

		monitorHook().run(taskName, () -> {
			int parallelCount2 = parallelCount;
			if (parallelCount2 > array.size()) {
				parallelCount2 = array.size();
			}

			// 任务队列
			Queue queueTasks = new LinkedList<>(array);

			while (!queueTasks.isEmpty()) {
				// 运行任务列表
				final List runningTasks = new ArrayList<>(parallelCount2);

				T task;

				for (int i = 0; i < parallelCount2; i++) {
					if ((task = queueTasks.poll()) != null) {
						runningTasks.add(task);
					}
					else {
						break;
					}
				}

				final CountDownLatch latch = new CountDownLatch(runningTasks.size());
				List> result = new ArrayList<>(parallelCount2);

				for (T obj : runningTasks) {
					Future future = monitorThreadPoolExecutor.submit(() -> {
						try {
							action.invoke(obj);
						}
						finally {
							latch.countDown();
						}
					});
					result.add(future);
				}

				try {
					latch.await();
				}
				catch (InterruptedException exp) {
					LogUtils.error(exp, "parallelFor 任务计数异常");
				}

				for (Future f : result) {
					try {
						f.get();
					}
					catch (Exception exp) {
						throw new BaseException("parallelFor并行执行出错", exp);
					}
				}
			}
			return 1;
		});
	}

	/**
	 * 任务使用固定并行大小处理任务,直到所有任务处理完毕。
	 *
	 * @param taskName      taskName
	 * @param parallelCount parallelCount
	 * @param array         array
	 * @param action        action
	 * @since 2021-09-02 20:48:25
	 */
	public  void monitorParallelFor2(
		String taskName, int parallelCount, Collection array, final Action1 action) {
		monitorThreadPoolCheckHealth();
		monitorHook().run(taskName, () -> {
			int parallelCount2 = parallelCount;
			if (parallelCount2 > array.size()) {
				parallelCount2 = array.size();
			}
			// 任务队列
			Queue queueTasks = new LinkedList<>(array);

			if (!queueTasks.isEmpty()) {
				final CountDownLatch latch = new CountDownLatch(parallelCount2);
				Object lock = new Object();
				Ref exceptionRef = new Ref<>(null);
				for (int i = 0; i < parallelCount2; i++) {
					monitorThreadPoolExecutor.submit(() -> {
						while (true) {
							T task;
							synchronized (lock) {
								task = queueTasks.poll();
							}

							if (task != null && exceptionRef.isNull()) {
								try {
									action.invoke(task);
								}
								catch (Exception exp) {
									latch.countDown();
									exceptionRef.setData(exp);
									break;
								}
							}
							else {
								latch.countDown();
								break;
							}
						}
					});
				}

				try {
					latch.await();
				}
				catch (InterruptedException exp) {
					LogUtils.error(exp, "parallelFor 任务计数异常");
				}
				if (!exceptionRef.isNull()) {
					throw new BaseException("parallelFor 并行执行出错", exceptionRef.getData());
				}
			}
			return 1;
		});
	}


	/**
	 * 使用系统线程池并行for循环
	 *
	 * @param taskName      任务名称
	 * @param parallelCount 并行数量
	 * @param taskList      任务列表
	 * @param action        action
	 * @since 2021-09-02 20:57:35
	 */
	public  void parallelFor(
		String taskName, int parallelCount, Collection taskList,
		final Action1 action) {
		if (parallelCount < 2) {
			for (T t : taskList) {
				action.invoke(t);
			}
		}
		else {
			monitorParallelFor2(taskName, parallelCount, taskList, action);
		}
	}


	/**
	 * 线程池分批执行某个方法(batchExecute(temList,storeCode1)),所有数据都执行完成后返回数据
	 *
	 * @param batchExecuteSize 批次执行的数量
	 * @param timeout          超时(分组)
	 * @param dataList         数据列表
	 * @param middleFunc       中间函数
	 * @param resultFunc       结果函数
	 * @return {@link List }<{@link R }>
	 * @since 2022-09-19 16:35:32
	 */
	public  List batchExecute(
		int batchExecuteSize,
		long timeout,
		List dataList,
		java.util.function.Function, M> middleFunc,
		java.util.function.Function resultFunc) {
		int totalSize = dataList.size();
		int totalPage = totalSize / batchExecuteSize;

		ExecutorService pool = new ThreadPoolExecutor(
			totalPage + 1, totalPage + 1, 0L, TimeUnit.MILLISECONDS,
			new LinkedBlockingQueue());

		List> futureList = new ArrayList<>();
		for (int pageNum = 1; pageNum <= totalPage + 1; pageNum++) {
			int starNum = (pageNum - 1) * batchExecuteSize;
			int endNum = Math.min(pageNum * batchExecuteSize, totalSize);
			List temList = dataList.subList(starNum, endNum);

			if (CollUtil.isNotEmpty(temList)) {
				Callable callable = () -> middleFunc.apply(temList);
				Future future = pool.submit(callable);
				futureList.add(future);
			}
		}
		pool.shutdown(); // 不允许再想线程池中增加线程

		List result = new ArrayList<>();
		try {
			// 判断是否所有线程已经执行完毕
			boolean isFinish = pool.awaitTermination(timeout, TimeUnit.MINUTES);
			// 如果没有执行完
			if (!isFinish) {
				// 线程池执行结束 不在等待线程执行完毕,直接执行下面的代码
				pool.shutdownNow();
			}

			result = futureList.stream()
				.map(e -> {
					try {
						return resultFunc.apply(e.get());
					}
					catch (InterruptedException | ExecutionException ex) {
						throw new RuntimeException(ex);
					}
				})
				.toList();
		}
		catch (Exception e) {
			LogUtils.error(e);
		}
		return result;
	}

	public ThreadPoolExecutor getMonitorThreadPoolExecutor() {
		return monitorThreadPoolExecutor;
	}

	public void setMonitorThreadPoolExecutor(ThreadPoolExecutor monitorThreadPoolExecutor) {
		this.monitorThreadPoolExecutor = monitorThreadPoolExecutor;
	}

	public ThreadPoolTaskExecutor getAsyncThreadPoolExecutor() {
		return asyncThreadPoolExecutor;
	}

	public void setAsyncThreadPoolExecutor(ThreadPoolTaskExecutor asyncThreadPoolExecutor) {
		this.asyncThreadPoolExecutor = asyncThreadPoolExecutor;
	}

	public MonitorThreadPoolProperties getMonitorThreadPoolProperties() {
		return monitorThreadPoolProperties;
	}

	public void setMonitorThreadPoolProperties(
		MonitorThreadPoolProperties monitorThreadPoolProperties) {
		this.monitorThreadPoolProperties = monitorThreadPoolProperties;
	}

	public AsyncProperties getAsyncThreadPoolProperties() {
		return asyncProperties;
	}

	public void setAsyncThreadPoolProperties(AsyncProperties asyncProperties) {
		this.asyncProperties = asyncProperties;
	}

	public Collector getCollector() {
		return collector;
	}

	public void setCollector(Collector collector) {
		this.collector = collector;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy