需求背景
📌最近遇到需要定时统计的任务,由于任务比较耗时,产品希望能在前端显示任务的实时统计进度。
使用说明
🥝创建用户类User.java
用户模拟定时任务批量处理用户信息
/**
* @author 赫兹
*/
@Data
@AllArgsConstructor
public class User {
private Long id;
private String name;
private String nickName;
private String sex;
private String email;
private int age;
}
🥝编写多线程工具类ThreadPoolUtil.java
,用于维护、管理线程池
/**
* @author 赫兹
*/
public class ThreadPoolUtil {
private static ThreadPoolExecutor threadPool;
private ThreadPoolUtil() {
throw new IllegalStateException("Utility class");
}
/**
* 无返回值,直接执行任务
*/
public static void execute(Runnable runnable) {
getThreadPool().execute(runnable);
}
/**
* 有返回值直,提交任务
*/
public static <T> Future<T> submit(Callable<T> callable) {
return getThreadPool().submit(callable);
}
/**
* 获取线程池
*
* @return 线程池对象
*/
public static ThreadPoolExecutor getThreadPool() {
if (threadPool != null) {
return threadPool;
} else {
synchronized (ThreadPoolUtil.class) {
if (threadPool == null) {
threadPool = new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200), new ThreadPoolExecutor.CallerRunsPolicy());
}
return threadPool;
}
}
}
}
🥝编写进度设置、进度查询工具类ProgressBarUtil.java
/**
* @author 赫兹
*/
public class ProgressBarUtil {
private ProgressBarUtil() {
throw new IllegalStateException("Utility class");
}
private static final ConcurrentHashMap<Long, Double> MAP = new ConcurrentHashMap<>();
/**
* 设置任务进度
*
* @param taskId 任务id
* @param progress 进度
*/
public static void setProcessBar(Long taskId, Double progress) {
int maximum = 100;
if (taskId == null || progress == null) {
throw new ApplicationException(ApplicationExceptionEnum.PARAM_NULL);
}
if (progress < 0 || progress > maximum) {
throw new ApplicationException(ApplicationExceptionEnum.PARAM_ERROR);
}
MAP.put(taskId, progress);
}
/**
* 根据任务id查询任务进度
*
* @param taskIds 待查询的任务id集合
* @return 任务id和进度值的映射
*/
public static Map<Long, Double> getTaskProcessMap(Collection<Long> taskIds) {
Map<Long, Double> map = new ConcurrentHashMap<>(4);
for (Long taskId : taskIds) {
Optional.ofNullable(MAP.get(taskId)).ifPresent(v -> map.put(taskId, v));
}
return map;
}
}
🥝编写单元测试,测试结果
/**
* @author 赫兹
*/
@Slf4j
public class JUnitTest {
@Test
public void testProgressBarUtil() throws InterruptedException {
//任务id
Long taskId = 1008666L;
//创建用户数据(模拟数据库查询操作),用于模拟批量处理用户信息任务,即任务task1需要处理3条用户数据
List<User> userList = new ArrayList<>();
for (int i = 0; i < 203; i++) {
User user = new User((long) i, "张三_"+i, "小张_"+i, "男", "1234567@qq.com", 23);
userList.add(user);
}
//模拟前端轮询每隔1秒查询任务进度接口
ThreadPoolUtil.execute(()->{
List<Long> taskIds= new ArrayList<>(Arrays.asList(taskId));
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<Long, Double> taskProcessMap = ProgressBarUtil.getTaskProcessMap(taskIds);
log.info("任务进度Map集合{}",taskProcessMap);
}
});
Thread.sleep(1000);
//开始处理用户信息,并设置任务进度
//统计任务集合
List<Future<String>> futureList = new ArrayList<>();
userList.forEach(user -> {
//将任务提交线程池管理
Future<String> threadResult = ThreadPoolUtil.submit(() -> {
//模拟处理用户的信息的业务耗时
Thread.sleep(1000);
return user.getName();
});
futureList.add(threadResult);
});
//设置每次任务计算完成后的进度
final BigDecimal[] progress = {BigDecimal.ZERO};
//任务进度条最大值
int maximum = 100;
//计算每个任务占总进度的占比
BigDecimal taskProgress = BigDecimal.valueOf(maximum).divide(BigDecimal.valueOf(userList.size()), 2, RoundingMode.HALF_DOWN);
//等待线程执行结果,所有线程执行完毕后,再继续
futureList.forEach(threadResult -> {
try {
//每次任务完成后,就加上进度
threadResult.get();
progress[0] = progress[0].add(taskProgress);
ProgressBarUtil.setProcessBar(taskId, progress[0].doubleValue());
} catch (InterruptedException | ExecutionException e) {
log.error(e.getMessage(), e);
Thread.currentThread().interrupt();
}
});
//任务执行完成后,将进度条设置100%(计算进度占比时,采用的去尾法取两位小数,因此任务统计完成后,进度可能会不足100%)
ProgressBarUtil.setProcessBar(taskId, 100.0);
//不让主线程这么快退出,为了让前端查询的子线程有更好模拟效果
Thread.sleep(60000);
}
}
🥝结果输出
15:58:30.807 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{}
15:58:31.817 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{}
15:58:32.829 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=1.47}
15:58:33.837 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=2.94}
15:58:34.840 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=4.41}
15:58:35.841 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=5.88}
15:58:36.852 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=7.35}
15:58:37.865 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=8.82}
15:58:38.874 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=10.29}
15:58:39.888 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=11.76}
15:58:40.901 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=13.23}
15:58:41.912 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=14.7}
15:58:42.922 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=16.17}
15:58:43.934 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=17.64}
15:58:44.937 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=19.11}
15:58:45.943 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=20.58}
15:58:46.947 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=22.05}
15:58:47.955 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=23.52}
15:58:48.965 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=25.48}
15:58:49.976 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=27.44}
15:58:50.992 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=27.93}
15:58:52.003 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=29.4}
15:58:53.009 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=30.87}
15:58:54.056 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=32.34}
15:58:55.063 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=33.81}
15:58:56.076 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=35.28}
15:58:57.085 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=36.75}
15:58:58.096 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=38.22}
15:58:59.109 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=39.69}
15:59:00.118 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=41.16}
15:59:01.123 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=42.63}
15:59:02.134 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=44.1}
15:59:03.147 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=47.04}
15:59:04.162 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=48.02}
15:59:05.174 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=48.51}
15:59:06.187 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=49.98}
15:59:07.189 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=51.45}
15:59:08.202 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=52.92}
15:59:09.214 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=54.39}
15:59:10.218 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=55.86}
15:59:11.232 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=57.33}
15:59:12.240 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=58.8}
15:59:13.250 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=60.27}
15:59:14.252 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=61.74}
15:59:15.260 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=63.21}
15:59:16.270 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=64.68}
15:59:17.276 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=66.15}
15:59:18.286 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=67.62}
15:59:19.297 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=69.09}
15:59:20.310 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=70.56}
15:59:21.323 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=73.5}
15:59:22.336 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=73.5}
15:59:23.349 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=74.97}
15:59:24.353 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=76.44}
15:59:25.363 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=78.4}
15:59:26.368 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=79.38}
15:59:27.378 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=80.85}
15:59:28.386 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=82.32}
15:59:29.396 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=83.79}
15:59:30.407 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=85.26}
15:59:31.412 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=86.73}
15:59:32.424 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=88.2}
15:59:33.439 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=89.67}
15:59:34.448 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=91.14}
15:59:35.458 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=92.61}
15:59:36.473 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=94.08}
15:59:37.483 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=95.55}
15:59:38.487 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=97.02}
15:59:39.495 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=98.49}
15:59:40.502 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=100.0}
15:59:41.512 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=100.0}
15:59:42.520 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=100.0}
15:59:43.526 [pool-1-thread-1] INFO com.hz.codecase.test.JUnitTest - 任务进度Map集合{1008666=100.0}
Process finished with exit code -1
评论区