Java多线程分批处理数据

博客介绍在发送大量短信场景下,可采用Java多线程分批处理以提高效率,同时要控制线程数量避免过度消耗CPU资源。还给出了创建分页类、线程类、实体类和主类的代码实现。

场景:发短信,当有数据量庞大的短信需要发送时,可以采用多线程的方式分批处理以提高效率,但线程要控制合适的数量,否则会极大消耗CPU资源

上代码:

创建分页类PageUtil

/**
 * 分页
 * @param list 切割数据集合
 * @param pageSize 每页记录数
 * @param <T>
 * @return
 */
public static <T> List<List<T>> splitList(List<T> list, int pageSize) {
        int listSize = list.size();
        int page = (listSize + (pageSize - 1)) / pageSize;
        List<List<T>> listArray = new ArrayList<List<T>>();
        for (int i = 0; i < page; i++) {
            List<T> subList = new ArrayList<T>();
            for (int j = 0; j < listSize; j++) {
                int pageIndex = ((j + 1) + (pageSize - 1)) / pageSize;
                if (pageIndex == (i + 1)) {
                    subList.add(list.get(j));
                }
                if ((j + 1) == ((j + 1) * pageSize)) {
                    break;
                }
            }
            listArray.add(subList);
        }
        return listArray;
    }

创建实现Runnable接口的线程类TestThread

public class TestThread implements Runnable{

    private List<UserEntity> userEntityList;

    public TestThread(List<UserEntity> userEntityList) {
        this.userEntityList = userEntityList;
    }

    @Override
    public void run() {
        for (UserEntity userEntity: userEntityList){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
            System.out.println("name:"+Thread.currentThread().getName()+userEntity.toString());
        }
    }
}

创建实体类UserEntity

public class UserEntity {

    private String userId;
    private String userName;

    public UserEntity() {
    }

    public UserEntity(String userId, String userName) {
        this.userId = userId;
        this.userName = userName;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "UserEntity{" +
                "userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                '}';
    }
}

创建主类BatchThread

public class BatchThread {

    public static void main(String[] args) {
        List<UserEntity> userList = initUser();
        int userCount = 2;
        List<List<UserEntity>> pageList = PageUtil.splitList(userList, userCount);
        for (int i = 0; i < pageList.size(); i++){
            List<UserEntity> userEntityList = pageList.get(i);
            TestThread testThread = new TestThread(userEntityList);
            Thread thread = new Thread(testThread);
            thread.start();
        }
    }

    public static List<UserEntity> initUser(){
        List<UserEntity> userEntityList = new ArrayList<>();
        for (int i = 1; i <= 11; i++){
            userEntityList.add(new UserEntity("id:"+i, "username:"+i));
        }
        return userEntityList;
    }
}

结果:

### Java 多线程环境下的分批写入数据Java多线程环境中,为了高效地处理大量数据并将其分批次写入目标存储介质(如数据库、文件等),可以采用线程池来管理多个工作线程。这种方式不仅能够提高程序执行效率,还能有效利用计算机资源。 对于具体应用场景——比如将大批量的数据记录保存到Excel文档中——可以通过以下方式实现: #### 使用线程池初始化与配置 创建固定大小的线程池用于并发操作,确保不会因为过多的同时运行的任务而耗尽系统资源。这一步骤通常是在应用程序启动初期完成[^1]。 ```java ExecutorService executor = Executors.newFixedThreadPool(5); // 创建拥有五个核心线程的工作队列 ``` #### 数据获取与分割 从源处取得待处理数据集之后,依据实际情况合理切分成若干个小部分交给不同线程去独立计算。这里假设有一个`List<List<Object>> dataList;`包含了所有要被写出的对象列表[^2]。 ```java int batchSize = 1000; for (int i = 0; i < dataList.size(); i += batchSize) { int endIndex = Math.min(i + batchSize, dataList.size()); List<Object> batchData = dataList.subList(i, endIndex); Runnable worker = new BatchWriteTask(batchData); executor.execute(worker); } ``` #### 定义任务类 `BatchWriteTask` 此自定义Runnable子类负责接收一批次的数据,并对其进行必要的转换后存入最终目的地,在这里是向Excel表单追加新行[^3]。 ```java class BatchWriteTask implements Runnable { private final List<Object> data; public BatchWriteTask(List<Object> data){ this.data = data; } @Override public void run() { try{ Workbook workbook = null; File file = new File("output.xlsx"); if (!file.exists()) { workbook = new XSSFWorkbook(); } else { FileInputStream fis = new FileInputStream(file); workbook = new XSSFWorkbook(fis); fis.close(); } Sheet sheet = workbook.getSheetAt(0); for(Object record : data){ Row row = sheet.createRow(sheet.getLastRowNum()+1); // 假设record是一个Map<String,Object>,可以根据实际需求调整 Map<String, Object> mapRecord = (Map<String, Object>) record; Cell cellA = row.createCell(0); cellA.setCellValue((String)mapRecord.get("columnA")); Cell cellB = row.createCell(1); cellB.setCellValue((Integer)mapRecord.get("columnB")); } FileOutputStream fos = new FileOutputStream(file,true); workbook.write(fos); fos.flush(); fos.close(); workbook.close(); } catch(Exception e){ System.err.println(e.getMessage()); } } } ``` #### 关闭线程池等待全部作业结束 当所有的提交都完成后,应当关闭线程池以防止新的请求加入进来,并调用awaitTermination阻塞当前线程直到所有已提交的任务都被取消或已完成执行. ```java executor.shutdown(); try { if (!executor.awaitTermination(800, TimeUnit.SECONDS)) { executor.shutdownNow(); } else { executor.shutdownNow(); } } catch (InterruptedException ie) { executor.shutdownNow(); } ``` 上述代码片段展示了如何在一个典型的Java应用里运用多线程机制来进行大数据量的分片式写入操作。需要注意的是,针对不同的业务逻辑和技术栈可能还需要做适当修改优化性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值