package com.csg.ui.cbhs.zhwh.action;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EnumMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* 任务调度器核心类 - 管理多类型任务的并发执行
*
* 功能特点:
* 1. 支持SHORT/MEDIUM/LONG三种任务类型
* 2. 资源池化管理(数据库连接/文件锁/服务调用)
* 3. 动态线程池调整
* 4. 完善的监控统计和日志系统
*
* 优化点:
* - 精简任务日志,仅记录异常和超长任务
* - 增强资源竞争处理机制
* - 改进监控报告逻辑
*/
public class TaskScheduler {
private static final Logger logger = Logger.getLogger(TaskScheduler.class.getName());
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
// 线程池配置
private static final int THREAD_POOL_CORE_SIZE = 100;
private static final int THREAD_POOL_MAX_SIZE = 400;
// 资源池配置
private static final int DB_CONNECTION_POOL_SIZE = 200;
private static final int FILE_LOCK_POOL_SIZE = 120;
private static final int MAX_SERVICE_CALLS = 500;
// 重试策略配置
private static final int DB_CONNECTION_MAX_RETRIES = 5;
private static final long DB_CONNECTION_BASE_DELAY_MS = 50;
private static final int FILE_LOCK_MAX_RETRIES = 5;
private static final long FILE_LOCK_BASE_DELAY_MS = 50;
// 日志级别配置
private static final Level TASK_DETAIL_LEVEL = Level.FINE;
private static final Level MONITOR_LEVEL = Level.INFO;
// 自定义日志格式化器
static class CustomFormatter extends Formatter {
@Override
public String format(LogRecord record) {
return String.format("[%s] %s: %s%n", dateFormat.format(new Date(record.getMillis())),
record.getLevel().getName(), formatMessage(record));
}
}
// 资源信号量
private static final Semaphore dbConnectionSemaphore = new Semaphore(DB_CONNECTION_POOL_SIZE, true);
private static final Semaphore fileLockSemaphore = new Semaphore(FILE_LOCK_POOL_SIZE, true);
private static final Semaphore serviceCallSemaphore = new Semaphore(MAX_SERVICE_CALLS);
static {
configureLogging();
}
/**
* 配置日志系统
* - 控制台输出INFO及以上级别
* - 文件输出ALL级别
*/
private static void configureLogging() {
try {
Logger rootLogger = Logger.getLogger("");
for (Handler handler : rootLogger.getHandlers()) {
rootLogger.removeHandler(handler);
}
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
FileHandler fileHandler = new FileHandler("TaskScheduler_LOG_" + date + ".log");
fileHandler.setFormatter(new CustomFormatter());
fileHandler.setLevel(Level.ALL);
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setFormatter(new CustomFormatter());
consoleHandler.setLevel(MONITOR_LEVEL);
Logger classLogger = Logger.getLogger(TaskScheduler.class.getName());
classLogger.setUseParentHandlers(false);
classLogger.addHandler(fileHandler);
classLogger.addHandler(consoleHandler);
classLogger.setLevel(Level.ALL);
} catch (Exception e) {
System.err.println("初始化日志失败: " + e.getMessage());
}
}
/**
* 任务类型枚举
* - SHORT: 短任务 (50%)
* - MEDIUM: 中等任务 (30%)
* - LONG: 长任务 (20%)
*/
enum TaskType {
SHORT(0.5, 1, 5), MEDIUM(0.3, 8, 15), LONG(0.2, 30, 60);
final double ratio;
final int minTime;
final int maxTime;
TaskType(double ratio, int minTime, int maxTime) {
this.ratio = ratio;
this.minTime = minTime;
this.maxTime = maxTime;
}
}
/**
* 任务计数器 - 原子化统计各类任务指标
*/
static class TaskCounters {
final AtomicInteger total = new AtomicInteger(0);
final AtomicInteger completed = new AtomicInteger(0);
final AtomicInteger failed = new AtomicInteger(0);
final Map<TaskType, AtomicInteger> typeCounts = new EnumMap<>(TaskType.class);
final Map<TaskType, LongAdder> typeDurations = new EnumMap<>(TaskType.class);
final ConcurrentHashMap<Integer, Long> taskStartTimes = new ConcurrentHashMap<>();
final ConcurrentHashMap<Integer, Long> taskDurations = new ConcurrentHashMap<>();
final ConcurrentHashMap<Integer, String> taskStatus = new ConcurrentHashMap<>();
TaskCounters() {
for (TaskType type : TaskType.values()) {
typeCounts.put(type, new AtomicInteger(0));
typeDurations.put(type, new LongAdder());
}
}
}
public static void main(String[] args) throws InterruptedException {
final int TOTAL_TASKS = 2000;
// 添加安全关闭钩子
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
logger.info("接收到关闭信号,准备终止系统...");
}));
logInfo("优化版任务调度器启动");
logInfo("配置参数: 线程池=%d-%d, 数据库连接=%d, 文件锁=%d, 服务调用=%d", THREAD_POOL_CORE_SIZE, THREAD_POOL_MAX_SIZE,
DB_CONNECTION_POOL_SIZE, FILE_LOCK_POOL_SIZE, MAX_SERVICE_CALLS);
TaskCounters counters = new TaskCounters();
ThreadPoolExecutor executor = new ThreadPoolExecutor(THREAD_POOL_CORE_SIZE, THREAD_POOL_MAX_SIZE, 30L,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(TOTAL_TASKS), new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(r -> {
Thread t = new Thread(r);
t.setName("task-worker-" + t.getId());
return t;
});
CountDownLatch latch = new CountDownLatch(TOTAL_TASKS);
long startTime = System.currentTimeMillis();
Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>();
for (int i = 1; i <= TOTAL_TASKS; i++) {
TaskType type = getRandomTaskType();
int duration = type.minTime + ThreadLocalRandom.current().nextInt(type.maxTime - type.minTime + 1);
taskQueue.add(createTask(i, type, duration, counters, latch));
}
logInfo("已生成 %d 个任务,开始执行...", TOTAL_TASKS);
startMonitorThread(executor, counters, TOTAL_TASKS);
long concurrentStart = System.currentTimeMillis();
taskQueue.forEach(executor::submit);
latch.await();
executor.shutdown();
// 等待线程池完全终止
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
logWarning("线程池未能在30秒内完全终止");
}
long concurrentDuration = System.currentTimeMillis() - concurrentStart;
long totalDuration = System.currentTimeMillis() - startTime;
printFinalStatistics(counters, TOTAL_TASKS, concurrentDuration, totalDuration);
}
/**
* 启动监控线程,定期报告系统状态
*/
private static void startMonitorThread(ThreadPoolExecutor executor, TaskCounters counters, int totalTasks) {
new Thread(() -> {
long lastReportTime = System.currentTimeMillis();
int lastCompleted = 0;
while (!executor.isTerminated()) {
try {
Thread.sleep(5000);
int completed = counters.completed.get() + counters.failed.get();
double progress = (completed * 100.0) / totalTasks;
long currentTime = System.currentTimeMillis();
int tasksSinceLast = completed - lastCompleted;
long timeSinceLast = currentTime - lastReportTime;
double tasksPerSec = timeSinceLast > 0 ? tasksSinceLast * 1000.0 / timeSinceLast : 0;
// 精简监控报告
logInfo("监控: [进度=%.1f%%, 活跃线程=%d/%d, 队列=%d, 速率=%.1f任务/秒, 资源: DB=%d/%d, 文件锁=%d/%d]", progress,
executor.getActiveCount(), executor.getPoolSize(), executor.getQueue().size(), tasksPerSec,
dbConnectionSemaphore.availablePermits(), DB_CONNECTION_POOL_SIZE,
fileLockSemaphore.availablePermits(), FILE_LOCK_POOL_SIZE);
lastCompleted = completed;
lastReportTime = currentTime;
adjustThreadPool(executor);
} catch (Exception e) {
// 忽略监控异常
}
}
}, "monitor-thread").start();
}
/**
* 动态调整线程池大小
*/
private static void adjustThreadPool(ThreadPoolExecutor executor) {
int queueSize = executor.getQueue().size();
int currentThreads = executor.getPoolSize();
// 基于队列长度智能调整
if (queueSize > 200) {
int increment = Math.min(50, executor.getMaximumPoolSize() - currentThreads);
if (increment > 0) {
executor.setCorePoolSize(currentThreads + increment);
logFine("线程池扩容: %d -> %d", currentThreads, currentThreads + increment);
}
} else if (queueSize < 50 && currentThreads > THREAD_POOL_CORE_SIZE) {
int decrement = Math.min(20, currentThreads - THREAD_POOL_CORE_SIZE);
executor.setCorePoolSize(currentThreads - decrement);
logFine("线程池缩容: %d -> %d", currentThreads, currentThreads - decrement);
}
}
// 日志辅助方法
private static synchronized void logInfo(String format, Object... args) {
logger.info(String.format(format, args));
}
private static synchronized void logFine(String format, Object... args) {
logger.log(TASK_DETAIL_LEVEL, String.format(format, args));
}
private static synchronized void logWarning(String format, Object... args) {
logger.warning(String.format(format, args));
}
/**
* 计算串行执行总时长
*/
private static long calculateSerialDuration(TaskCounters counters) {
return counters.taskDurations.values().stream().mapToLong(Long::longValue).sum();
}
/**
* 打印最终统计信息
*/
private static void printFinalStatistics(TaskCounters counters, int totalTasks, long concurrentDuration,
long totalDuration) {
logInfo("==================== 任务执行完成 ====================");
logInfo("总任务数: %d, 成功: %d, 失败: %d, 成功率: %.2f%%", totalTasks, counters.completed.get(), counters.failed.get(),
(counters.completed.get() * 100.0) / totalTasks);
logInfo("并发执行耗时: %.2f秒", concurrentDuration / 1000.0);
logInfo("程序总耗时: %.2f秒", totalDuration / 1000.0);
long serialDuration = calculateSerialDuration(counters);
logInfo("串行执行预估耗时: %.2f秒", serialDuration / 1000.0);
logInfo("并发加速比: %.2fx", (double) serialDuration / concurrentDuration);
logInfo("==================== 任务类型统计 ====================");
for (TaskType type : TaskType.values()) {
int count = counters.typeCounts.get(type).get();
long totalTime = counters.typeDurations.get(type).sum();
logInfo("%-6s: 数量=%d (%.1f%%), 平均耗时=%.2fs, 总耗时=%.2fs", type, count, count * 100.0 / totalTasks,
totalTime / 1000.0 / Math.max(1, count), totalTime / 1000.0);
}
verifyTaskExecution(counters, totalTasks);
}
/**
* 验证任务执行完整性
*/
private static void verifyTaskExecution(TaskCounters counters, int totalTasks) {
int completed = counters.completed.get();
int failed = counters.failed.get();
int recorded = counters.taskDurations.size();
logInfo("==================== 任务验证 ====================");
logInfo("应完成任务数: %d", totalTasks);
logInfo("成功任务数: %d", completed);
logInfo("失败任务数: %d", failed);
logInfo("已记录耗时任务数: %d", recorded);
if (completed + failed == totalTasks && recorded == completed) {
logInfo("所有任务均已执行! 成功: %d, 失败: %d", completed, failed);
} else {
logWarning("部分任务可能未执行或未记录耗时!");
}
if (failed > 0) {
Map<String, AtomicInteger> failureReasons = new ConcurrentHashMap<>();
counters.taskStatus.forEach((id, status) -> {
if (status.startsWith("FAILED")) {
String reason = status.split(":")[1].trim();
failureReasons.computeIfAbsent(reason, k -> new AtomicInteger()).incrementAndGet();
}
});
logInfo("==================== 失败原因统计 ====================");
failureReasons.forEach(
(reason, count) -> logInfo("%s: %d (%.1f%%)", reason, count.get(), count.get() * 100.0 / failed));
}
}
/**
* 随机获取任务类型
*/
private static TaskType getRandomTaskType() {
double r = ThreadLocalRandom.current().nextDouble();
if (r < TaskType.SHORT.ratio)
return TaskType.SHORT;
if (r < TaskType.SHORT.ratio + TaskType.MEDIUM.ratio)
return TaskType.MEDIUM;
return TaskType.LONG;
}
/**
* 创建任务实例
*/
private static Runnable createTask(int id, TaskType type, int duration, TaskCounters counters,
CountDownLatch latch) {
return () -> {
long start = System.currentTimeMillis();
counters.taskStartTimes.put(id, start);
counters.taskStatus.put(id, "STARTED");
try {
serviceCallSemaphore.acquire();
try {
executeBusinessOperation(id, type, duration);
long taskDuration = System.currentTimeMillis() - start;
counters.typeCounts.get(type).incrementAndGet();
counters.typeDurations.get(type).add(taskDuration);
counters.completed.incrementAndGet();
counters.taskDurations.put(id, taskDuration);
counters.taskStatus.put(id, "COMPLETED");
// 仅记录超长任务(超过预期3倍或60秒)
if (taskDuration > duration * 3000 || taskDuration > 60_000) {
logInfo("长时任务 #%d (%s): 预计=%ds, 实际=%.1fs", id, type, duration, taskDuration / 1000.0);
}
} finally {
serviceCallSemaphore.release();
}
} catch (Exception e) {
long taskDuration = System.currentTimeMillis() - start;
counters.failed.incrementAndGet();
counters.taskStatus.put(id, "FAILED: " + e.getClass().getSimpleName());
// 记录所有失败任务
logWarning("任务 #%d (%s) 失败: 预计=%ds, 实际=%.1fs, 原因=%s", id, type, duration, taskDuration / 1000.0,
e.getMessage());
} finally {
latch.countDown();
}
};
}
/**
* 执行业务操作
*/
private static void executeBusinessOperation(int taskId, TaskType type, int duration) throws Exception {
int operationType = ThreadLocalRandom.current().nextInt(100);
if (operationType < 40) {
simulateCpuIntensiveWork(duration);
} else {
simulateDatabaseOperation(duration);
}
}
/**
* 模拟CPU密集型操作
*/
private static void simulateCpuIntensiveWork(int seconds) {
long endTime = System.nanoTime() + seconds * 1_000_000_000L;
while (System.nanoTime() < endTime) {
double result = 0;
for (int i = 0; i < 10000; i++) {
result += Math.sqrt(i) * Math.sin(i);
}
}
}
/**
* 模拟数据库操作(使用指数退避重试策略)
*/
private static void simulateDatabaseOperation(int seconds) throws Exception {
long baseDelay = DB_CONNECTION_BASE_DELAY_MS;
for (int retry = 0; retry < DB_CONNECTION_MAX_RETRIES; retry++) {
if (dbConnectionSemaphore.tryAcquire(200, TimeUnit.MILLISECONDS)) {
try {
int workTime = seconds * 1000 - 200;
if (workTime > 0) {
simulateCpuIntensiveWork(workTime / 2000);
Thread.sleep(workTime / 2);
}
return;
} finally {
dbConnectionSemaphore.release();
}
}
// 指数退避 + 随机抖动
Thread.sleep(baseDelay * (1 << retry) + ThreadLocalRandom.current().nextInt(50, 200));
}
throw new RuntimeException("数据库连接获取失败");
}
}
有没有更好的办法来模拟真实的业务操作,不用数据库连接和文件锁这种方式