java
package com.fm.boot.util;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.*;
import java.time.Duration;
import java.time.Instant;
@Slf4j
public class ProgressTracker {
private final AtomicInteger completedTasks = new AtomicInteger(0);
private final int totalTasks;
private final String taskName;
private ScheduledExecutorService scheduler;
private Instant startTime;
private final ExecutorService executor;
public ProgressTracker(int totalTasks, String taskName, ExecutorService executor) {
this.totalTasks = totalTasks;
this.taskName = taskName;
this.executor = executor;
}
// 启动进度监控
public void start() {
startTime = Instant.now();
scheduler = Executors.newSingleThreadScheduledExecutor();
// 每秒输出一次进度
scheduler.scheduleAtFixedRate(this::logProgress, 0, 5, TimeUnit.SECONDS);
}
// 停止进度监控
public void stop() {
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdown();
executor.shutdown();
}
}
// 增加已完成的任务
public void increment() {
completedTasks.incrementAndGet();
}
private void logProgress() {
if (completedTasks.get() >= totalTasks) {
stop();
return;
}
int current = completedTasks.get();
// 避免除以零
if (current == 0) {
return;
}
double progress = (double) current / totalTasks * 100;
// 计算已花费时间和剩余时间
long elapsedTime = Duration.between(startTime, Instant.now()).toMillis();
long estimatedTime = (elapsedTime * totalTasks) / current;
long remainingTime = estimatedTime - elapsedTime;
// 格式化时间为易读格式
String elapsedTimeStr = formatTime(elapsedTime);
String estimatedTimeStr = formatTime(estimatedTime);
String remainingTimeStr = formatTime(remainingTime);
// 个/s
long ps = current / (elapsedTime / 1000);
// s/个
long sp = ((elapsedTime / 1000) / current);
log.info("[{}] 当前进度: {}/{} ({}%) 已花费时间: {} 预计总时间: {} 剩余时间: {} - {}个/s - {}s/个",
taskName, current, totalTasks, (int) progress,
elapsedTimeStr, estimatedTimeStr, remainingTimeStr, ps, sp);
}
// 格式化时间为小时、分钟、秒
private String formatTime(long millis) {
if (millis >= 3600000) {
long hours = millis / 3600000;
long minutes = (millis % 3600000) / 60000;
return String.format("%dh %dm", hours, minutes);
} else if (millis >= 60000) {
long minutes = millis / 60000;
long seconds = (millis % 60000) / 1000;
return String.format("%dm %ds", minutes, seconds);
} else {
long seconds = millis / 1000;
return String.format("%ds", seconds);
}
}
}