System.currentTimeMillis频繁打印耗时的封装类

package com.zhou.util;

import lombok.extern.slf4j.Slf4j;

/**
 * 过程计时器
 * @author lang.zhou
 * @since 2022/10/25 10:34
 */
@Slf4j
public class TimeCounter {

    private String name = "";

    /**
     * 开始执行时间
     */
    private final boolean debug ;

    /**
     * 开始执行时间
     */
    private final Long t0 ;

    /**
     * 上一次打印时间
     */
    private Long lastT ;


    public TimeCounter() {
        this("");
    }

    public TimeCounter(String name) {
        this(name,false);
    }

    public TimeCounter(String name, boolean debug) {
        this.name = name;
        this.debug = debug;
        this.lastT = t0 = System.currentTimeMillis();
    }



    /**
     * 打印距离上个时间的耗时
     */
    public long print(String msg, Object... args){
        Long t = System.currentTimeMillis();
        long dt = t - lastT;
        String info = String.format(msg,args);
        if(debug){
            log.debug("{}[{}]耗时{}",getNameStr(),info, dt);
        }else{
            log.info("{}[{}]耗时{}",getNameStr(),info, dt);
        }
        lastT = t;
        return dt;
    }

    private String getNameStr(){
        return StringTool.isBlank(name) ? "" : "【" + name + "】";
    }

    /**
     * 重置上个时间
     */
    public void reset(){
        lastT = System.currentTimeMillis();
    }

    /**
     * 总耗时
     */
    public long total(String msg, Object... args){
        String info = String.format(msg,args);
        long total = System.currentTimeMillis() - t0;
        if(debug){
            log.debug("{}[{}]{}",getNameStr(),info,total);
        }else{
            log.info("{}[{}]{}",getNameStr(),info,total);
        }
        return total;
    }
}
TimeCounter c = new TimeCounter();
//do something
c.print("操作1");
//do something
c.print("操作2");
//do something
c.reset();
//do something
c.print("操作3");
c.total("总耗时");

public void fixResignedEmployeeStatus() { int batchSize = 500; int offset = 0; boolean hasMoreData = true; long totalStartTime = System.currentTimeMillis(); int totalProcessed = 0; int totalUpdated = 0; RedisTemplate<Serializable, Object> redisServiceTemplate = redisService.getTemplate(); log.info("开始批量处理离职员工数据,总批次预估:{}", (userBaseInfoService.count() + batchSize - 1) / batchSize); while (hasMoreData) { long batchStartTime = System.currentTimeMillis(); StringBuilder batchLog = new StringBuilder("批次[") .append(offset / batchSize + 1).append("] "); try { // 1. 查询用户数据 long queryStart = System.currentTimeMillis(); List<UserInfo> batchUsers = userBaseInfoService.lambdaQuery() .last("LIMIT " + offset + ", " + batchSize) .list(); long queryTime = System.currentTimeMillis() - queryStart; if (CollectionUtil.isEmpty(batchUsers)) { hasMoreData = false; batchLog.append("无更多数据"); continue; } totalProcessed += batchUsers.size(); // 2. 提取员工号 long extractStart = System.currentTimeMillis(); List<String> empNos = batchUsers.stream() .map(UserInfo::getEmployeeNo) .collect(Collectors.toList()); long extractTime = System.currentTimeMillis() - extractStart; // 3. 调用外部接口 long apiStart = System.currentTimeMillis(); OpenResponse<List<UserDTO>> response = userService.batchQueryByEmpNos(empNos); long apiTime = System.currentTimeMillis() - apiStart; // 4. 准备更新数据 long processStart = System.currentTimeMillis(); List<UserInfo> usersToUpdate = new ArrayList<>(); List<UserBaseInfo> usersToCache = new ArrayList<>(); Set<String> activeEmpNos = Collections.emptySet(); if (response != null && CollectionUtil.isNotEmpty(response.getData())) { activeEmpNos = response.getData().stream() .map(UserDTO::getEmployeeNo) .collect(Collectors.toSet()); } for (UserInfo user : batchUsers) { if (!activeEmpNos.contains(user.getEmployeeNo()) && user.getIsOnDuty() != 0) { user.setIsOnDuty(0); usersToUpdate.add(user); // 保持原有缓存处理逻辑 UserBaseInfo cacheUser = new UserBaseInfo(); BeanUtil.copyProperties(user, cacheUser); usersToCache.add(cacheUser); } } long processTime = System.currentTimeMillis() - processStart; // 5. 批量更新 long updateStart = System.currentTimeMillis(); if (CollectionUtil.isNotEmpty(usersToUpdate)) { userBaseInfoService.updateBatchById(usersToUpdate); totalUpdated += usersToUpdate.size(); } long updateTime = System.currentTimeMillis() - updateStart; // 6. 处理缓存 long cacheStart = System.currentTimeMillis(); for (UserBaseInfo cacheUser : usersToCache) { UserBaseInfo user = redisService.getObject(CacheConstant.CACHE_NAME_USER_BASE_INFO_KEY, cacheUser.getEmployeeNo()); if(ObjectUtil.isEmpty(user)){ setupUserDepartmentHierarchy(cacheUser); putUserInfoToCache(cacheUser); }else{ user.setIsOnDuty(0); putUserInfoToCache(user); } } long cacheTime = System.currentTimeMillis() - cacheStart; // 记录批次耗时 batchLog.append(String.format( "处理:%d条 | 查询:%dms | 提取:%dms | 接口:%dms | 处理:%dms | 更新:%dms | 缓存:%dms | 更新数:%d", batchUsers.size(), queryTime, extractTime, apiTime, processTime, updateTime, cacheTime, usersToUpdate.size())); } catch (Exception e) { batchLog.append("处理失败:").append(e.getMessage()); log.error(batchLog.toString(), e); } finally { offset += batchSize; long batchTime = System.currentTimeMillis() - batchStartTime; batchLog.append(" | 批次总耗时:").append(batchTime).append("ms"); log.info(batchLog.toString()); } } long totalTime = System.currentTimeMillis() - totalStartTime; log.info("处理完成!总计处理:{}条,更新:{}条,总耗时:{}ms(约{}秒)", totalProcessed, totalUpdated, totalTime, totalTime/1000); } private void putUserInfoToCache(UserBaseInfo user) { redisService.putObject(CacheConstant.CACHE_NAME_USER_BASE_INFO_KEY, String.valueOf(user.getUId()), user); redisService.putObject(CacheConstant.CACHE_NAME_USER_BASE_INFO_KEY, user.getEmployeeNo(), user); } 使用redisServiceTemplate这个分成两个Redis事务一次性提交加快速度 if(ObjectUtil.isEmpty(user)){ setupUserDepartmentHierarchy(cacheUser); putUserInfoToCache(cacheUser); }else{ user.setIsOnDuty(0); putUserInfoToCache(user); }
08-13
// 在 ProductAdapter 类中添加线程池 private static final ExecutorService IMAGE_PROCESSING_EXECUTOR = Executors.newFixedThreadPool(Math.max(5, Runtime.getRuntime().availableProcessors())); private ProductDTO photo(ProductDTO productDTO) { long startTime = System.currentTimeMillis(); if (ObjectUtil.isEmpty(productDTO)) { return null; } try { // 商品主图 CompletableFuture<FileRecordDTO> mainImageFuture = CompletableFuture.supplyAsync(() -> processSingleImage(productDTO.getMainImage()), IMAGE_PROCESSING_EXECUTOR) .exceptionally(throwable -> { System.err.println("处理主图失败: " + throwable.getMessage()); return null; }); // 商品详情图 CompletableFuture<List<FileRecordDTO>> detailImagesFuture = CompletableFuture.supplyAsync(() -> processMultipleImages(productDTO.getDetailDescImg()), IMAGE_PROCESSING_EXECUTOR) .exceptionally(throwable -> { System.err.println("处理详情图失败: " + throwable.getMessage()); return null; }); // 轮播推荐图 CompletableFuture<FileRecordDTO> promotionImageFuture = CompletableFuture.supplyAsync(() -> processSingleImage(productDTO.getProductPromotionImage()), IMAGE_PROCESSING_EXECUTOR) .exceptionally(throwable -> { System.err.println("处理轮播图失败: " + throwable.getMessage()); return null; }); // 商品副图 CompletableFuture<List<FileRecordDTO>> subImagesFuture = CompletableFuture.supplyAsync(() -> processMultipleImages(productDTO.getSubImages()), IMAGE_PROCESSING_EXECUTOR) .exceptionally(throwable -> { System.err.println("处理副图失败: " + throwable.getMessage()); return null; }); // 商品成分图 CompletableFuture<List<FileRecordDTO>> ingredientImagesFuture = CompletableFuture.supplyAsync(() -> processMultipleImages(productDTO.getIngredientImg()), IMAGE_PROCESSING_EXECUTOR) .exceptionally(throwable -> { System.err.println("处理成分图失败: " + throwable.getMessage()); return null; }); // 统一等待所有异步任务完成 CompletableFuture<Void> allTasks = CompletableFuture.allOf( mainImageFuture, detailImagesFuture, promotionImageFuture, subImagesFuture, ingredientImagesFuture); try { // 设置5秒超时 mainImageFuture.get(2, TimeUnit.SECONDS); allTasks.get(5, TimeUnit.SECONDS); } catch (TimeoutException e) { System.err.println("图片处理超时,使用部分结果"); } catch (Exception e) { System.err.println("等待图片处理任务完成时发生异常: " + e.getMessage()); } // 设置处理结果 productDTO.setMainImage(mainImageFuture.join()); productDTO.setDetailDescImg(detailImagesFuture.join()); productDTO.setProductPromotionImage(promotionImageFuture.join()); productDTO.setSubImages(subImagesFuture.join()); productDTO.setIngredientImg(ingredientImagesFuture.join()); } finally { long endTime = System.currentTimeMillis(); long executionTime = endTime - startTime; System.out.println("图片方法执行时间: " + executionTime + " 毫秒"); } return productDTO; } 使用的是jdk21
最新发布
12-11
使用的是springboot , 数据库连接使用jdbc进行连接,现在有一个sql拦截器,代码如下 Intercepts(value = { @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) @Slf4j public class SqlStatementInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object returnValue; long start = System.currentTimeMillis(); returnValue = invocation.proceed(); long end = System.currentTimeMillis(); long time = end - start; try { final Object[] args = invocation.getArgs(); //获取原始的ms MappedStatement ms = (MappedStatement)args[0]; Logger logger = LoggerFactory.getLogger(ms.getId()); Object parameter = null; //获取参数,if语句成立,表示sql语句有参数,参数格式是map形式 if (invocation.getArgs().length > 1) { parameter = invocation.getArgs()[1]; } // BoundSql就是封装myBatis最终产生的sql类 BoundSql boundSql = ms.getBoundSql(parameter); // 获取节点的配置 Configuration configuration = ms.getConfiguration(); //getSql(configuration, boundSql, sqlId, time); // 获取到最终的sql语句 String sql = showSql(configuration, boundSql); String namespace = ms.getId(); List<String> methodNames = Optional.ofNullable(LoaderAnnotation.getAnnoMap().get(NoFilter.class)).orElse(new ArrayList<>()); // 使用执行器的日志打印 if (methodNames.contains(NoFilterAspect.methodName.get()) || methodNames.contains(namespace)) { if (logger.isDebugEnabled()) { logger.debug("耗时【{}ms】,SQL: {}", time, sql); } if (logger.isDebugEnabled()) { logger.debug("result->{}", JacksonUtil.obj2json(returnValue)); } } else { logger.info("耗时【{}ms】,SQL: {}", time, sql); logger.info("result->{}", JacksonUtil.obj2json(returnValue)); } } catch (Exception e) { log.error("拦截sql处理出差{}", e.getMessage()); } return returnValue; } 我希望在上述代码中加入实时监控数据库连接池信息,如何实现
07-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值