1. 批量操作:高效处理大量数据

对数据List分页,处理后可以先保存到MQ, 插入主表记录,MQ消费保存明细记录和日志记录

List<List<Long>> allIds = Lists.partition(ids,200);

查询数据时,可以组装为ids, 批量查询或删除.

2. 异步处理:解放接口响应

public UserInfo getUserInfo(Long id) throws InterruptedException, ExecutionException
{
    final UserInfo userInfo = new UserInfo();
    CompletableFuture userFuture = CompletableFuture.supplyAsync(() - >
    {
        getRemoteUserAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
    CompletableFuture bonusFuture = CompletableFuture.supplyAsync(() - >
    {
        getRemoteBonusAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
    CompletableFuture growthFuture = CompletableFuture.supplyAsync(() - >
    {
        getRemoteGrowthAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
    CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join();
    userFuture.get();
    bonusFuture.get();
    growthFuture.get();
    return userInfo;
}

3. 缓存利用:用空间换时间

4. 预处理:提前做好准备工作

预取思想很容易理解,就是提前把要计算查询的数据,初始化到缓存。如果你在未来某个时间需要用到某个经过复杂计算的数据,才实时去计算的话,可能耗时比较大

5. 池化资源:避免重复创建

6. 并行执行:充分利用多核优势

7. 索引优化:为数据检索插上翅膀

8. 避免大事务:保持事务的精简

10. 深分页优化:破解分页性能难题

12. 锁粒度控制:找到并发访问的平衡点

13. 数据压缩:减少网络传输的负担

14. 服务拆分:让接口更专注高效

第一种

第二种:

列表10000条,

先拆分为100个大小100的list,分批操作.

100个list循环提交线程池,调用接口,并返回结果.

不直接更新数据库, 每100个批次,保存到redis或者MQ. 异步保存明细或日志.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BatchCall {
    private static final Logger logger = LoggerFactory.getLogger(BatchCall.class);
    private static final int BATCH_SIZE = 8;
    private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(BATCH_SIZE);

    public static void main(String[] args) {
        try {
            // 模拟待处理数据;
            List<T> dataList = new ArrayList<>(10000);
            //guava的分页工具
            //List<List<Long>> allIds = Lists.partition(ids,200);
            /*循环*/
            AtomicInteger batchIndex = new AtomicInteger(0);

            while (batchIndex.get() * BATCH_SIZE < dataList.size()) {
                int currentBatchIndex = batchIndex.getAndIncrement();
                CountDownLatch latch = new CountDownLatch(BATCH_SIZE);
                List<T> batch = getBatch(dataList, currentBatchIndex, BATCH_SIZE);

                for (T data : batch) {
                    executorService.submit(() -> {
                        try {
                            processData(data, latch);
                        } catch (Exception e) {
                            logger.error("Error processing data: " + data, e);
                            // 考虑是否需要在出现异常时让latch减计数
                            latch.countDown();
                        }
                    });
                }

                latch.await(); // 等待所有任务完成
                logger.info("Batch {} processed successfully.", currentBatchIndex + 1);
            }
        } catch (InterruptedException e) {
            logger.error("Processing interrupted", e);
            Thread.currentThread().interrupt();
        } finally {
            /*最好写在系统优雅停机时触发*/
            shutdown(executorService);
        }
    }
    // 提取批次数据的逻辑
    private static List<T> getBatch(List<T> dataList, int batchIndex, int batchSize) {
        return dataList.subList(batchIndex*batchSize,(batchIndex+1)*batchSize-1);

    }

    /**
     * @param data
     * @param latch
     * @throws InterruptedException
     * 调用第三方平台
     */
    private static void processData(T data, CountDownLatch latch) throws InterruptedException {

        TimeUnit.SECONDS.sleep(1);
        logger.info("Data processed: {}", data);
        /*处理完一笔交易,就 -1 */
        latch.countDown();
    }

    /**
     * @param service
     * 关闭线程池
     */
    private static void shutdown(ScheduledExecutorService service) {
        service.shutdown(); // 尝试优雅关闭线程池,等待线程处理完
        try {
            if (!service.awaitTermination(60, TimeUnit.SECONDS)) {
                service.shutdownNow(); // 强制关闭线程池,不等待线程处理结果
            }
        } catch (InterruptedException e) {
            service.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
后端 Java
喜欢就支持一下吧