自定义线程池跑批量任务

使用场景:需要批量处理数据,或者执行耗时任务,使用线程池处理,可提高效率,同时也方便对线程进行统一管理

创建线程池

// 创建一个并发数为10的线程池
ExecutorService mExecutor = Executors.newFixedThreadPool(10);

创建一个实体类,用来生成本次任务需要建立的数据

import java.math.BigDecimal;

public class DeductLog {

    private String caseSn; // 案件号
    private BigDecimal deductPmt;// 扣款金额

    public String getCaseSn() {
        return caseSn;
    }

    public void setCaseSn(String caseSn) {
        this.caseSn = caseSn;
    }

    public BigDecimal getDeductPmt() {
        return deductPmt;
    }

    public void setDeductPmt(BigDecimal deductPmt) {
        this.deductPmt = deductPmt;
    }
    
}

建立任务

这里的任务主要是针对单个的耗时任务

import java.math.BigDecimal;
import java.util.concurrent.Callable;

public class QuoteTask implements Callable<DeductLog> {

    public String caseSn;

    public QuoteTask(String caseSn) {
        this.caseSn = caseSn;
    }

    @Override
    public DeductLog call() throws Exception {
        // 模拟耗时操作
        Thread.sleep(100);
        // 操作结束,得到我们想要的数据
        DeductLog deductLog = new DeductLog();
        deductLog.setCaseSn(caseSn);
        deductLog.setDeductPmt(BigDecimal.TEN);
        return deductLog;
    }

}

提交任务

这里提交任务分为2种
invokeAll(tasks) 批量提交不限时任务
invokeAll(tasks, timeout, unit) 批量提交限时任务
InvokeAll方法处理一个任务的容器(collection),并返回一个Future的容器。两个容器具有相同的结构:
invokeAll将Future添加到返回的容器中,这样可以使用任务容器的迭代器,从而调用者可以将它表现的Callable与Future 关联起来。
当所有任务都完成时、调用线程被中断时或者超过时限时,限时版本的invokeAll都会返回结果。 超过时限后,任务尚未完成的任务都会被取消

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.*;

public class InvokeAllThread {
    // 固定大小的线程池
    static ExecutorService mExecutor = Executors.newFixedThreadPool(10);

    /**
     * 执行批量任务
     * 多线程产生大批量资料
     *
     * @return
     */
    public static List<DeductLog> getRankedTravelQuotes(List<QuoteTask> tasks) throws InterruptedException {
        /**
         * 使用invokeAll方法批量提交限时任务任务,预期15s所有任务都执行完,没有执行完的任务会自动取消
         */
//        List<Future<DeductLog>> futures = mExecutor.invokeAll(tasks, 15, TimeUnit.SECONDS);
        /**
         * 使用不限时的任务
         */
        List<Future<DeductLog>> futures = mExecutor.invokeAll(tasks);
        // 需要返回的资料
        List<DeductLog> deductLogList = new ArrayList<>();

        Iterator<QuoteTask> taskIter = tasks.iterator();

        for (Future<DeductLog> future : futures) {
            QuoteTask task = taskIter.next();
            try {
                deductLogList.add(future.get());
            } catch (ExecutionException e) {
                e.printStackTrace();
                System.out.println("任务异常,案件号是" + task.caseSn);
            } catch (CancellationException e) {
                e.printStackTrace();
                System.out.println("任务超时,案件号是" + task.caseSn);
            }
        }

        // 关闭线程池
        mExecutor.shutdown();

        return deductLogList;
    }
    
}

测试

创建一个测试数据,丢到线程池里,使用不限时的方式执行

public static void main(String[] args) throws Exception {
        // 创建批量任务
        List<QuoteTask> tasks = new ArrayList<>();
        for (int i = 1; i <= 200; i++) {
            tasks.add(new QuoteTask(System.currentTimeMillis() + "" + i));
        }

        // 多线程跑任务
        long start = System.currentTimeMillis();
        List<DeductLog> deductLogList = InvokeAllThread.getRankedTravelQuotes(tasks);
        long end = System.currentTimeMillis();
        System.out.println("多线程处理结束:" + deductLogList.size());
        System.out.println("多线程执行总耗时:" + (end - start) / 1000 + "s");

        // 单线程跑任务
        start = System.currentTimeMillis();
        deductLogList = new ArrayList<>();
        for (QuoteTask quoteTask : tasks) {
            deductLogList.add(quoteTask.call());
        }
        end = System.currentTimeMillis();
        System.out.println("单线程处理结束:" + deductLogList.size());
        System.out.println("单线程执行总耗时:" + (end - start) / 1000 + "s");
    }

结果

执行耗时结果如下图所示,由此可见,多线程的效率还是可以的
在这里插入图片描述
如果使用spring框架,推荐使用自带的线程池,参考

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线程池自定义线程池工厂指的是我们可以通过自定义工厂类来创建线程池。在Java中,我们可以通过实现ThreadFactory接口来自定义线程池工厂。通过自定义工厂类,我们可以定制线程的创建方式,例如给线程设置特定的命名规则、设置线程的优先级等。 自定义线程池工厂的步骤如下: 1. 创建一个实现ThreadFactory接口的自定义工厂类,并实现其`newThread(Runnable r)`方法。 2. 在`newThread`方法中,我们可以通过`Thread`类的构造方法来创建线程,并进行一些定制化的操作,比如设置线程的名称、优先级等。 3. 自定义线程池工厂类的实例化后,我们可以将其作为参数传递给线程池创建方法中,以便使用自定义线程池工厂来创建线程池。 举个例子,假设我们需要自定义线程池工厂来创建线程池,可以按照以下步骤进行: 1. 创建一个自定义线程池工厂类,例如`CustomThreadFactory`,并实现ThreadFactory接口。 2. 在`CustomThreadFactory`类中,实现`newThread(Runnable r)`方法,并在该方法中创建线程,并设置线程的名称。 3. 在使用线程池的地方,例如`Executors.newFixedThreadPool()`方法中,将`CustomThreadFactory`类的实例传递给`newFixedThreadPool()`方法,以使用自定义线程池工厂来创建线程池。 通过自定义线程池工厂,我们可以更加灵活地控制线程的创建过程,并根据实际需求进行定制化操作。这样可以提高线程池的灵活性和可扩展性,使其更好地适用于各种场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值