java使用线程池批量插入mysql数据

首先我们使用最原始的for循环插入数据:

for (int i = 0; i < 100000000; i++) {
            service.add(new LongTest().setStatus(1).
                    setName(NumberUtil.getPwdRandom(5)));
        }

通过上面的操作大概每3秒可以插入数据库1000条数据,这样效率太慢了。我们下面将换成线程池进行数据插入。

定义线程池常量类

/**
 * 线程池常量.
 */
public class ThreadPoolConstant {

    /**
     * 核心线程数量
     */
    public static final int CORE_THREAD_NUM = 10;

    /**
     * 最大线程数量
     */
    public static final int MAX_THREAD_NUM = 15;

    /**
     * 非核心线程存活时间
     */
    public static final long KEEP_ALIVE_TIME_SECONDS = 10L;

    /**
     * 任务队列长度
     */
    public static final int QUEUE_LENGTH = 20;

    /**
     * 线程超时时间
     */
    public static final long TIME_OUT = 70;

}

创建线程池执行线程(当日创建线程池的发放有好几种,我们就不一一举例了,我们只列出最简单的一种演示即可)

// 执行任务
        // 创建线程池(线程池大小、最大线程数、保持存活时间(线程空闲时间超过会退出线程)、时间单位)
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                ThreadPoolConstant.CORE_THREAD_NUM
                , ThreadPoolConstant.MAX_THREAD_NUM,
                ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(ThreadPoolConstant.QUEUE_LENGTH),Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.CallerRunsPolicy());
        // 执行任务
        for (int i = 0; i < 100000000; i++) {
            final int index = i;
            threadPool.execute(() -> {
Thread.currentThread().getName()+"\n");
                service.add(new LongTest().setStatus(1).
                        setName(NumberUtil.getPwdRandom(5)));
            });

        }

通过上面的线程池代码插入数据,相比传统的数据插入,使用线程池的效率提高了百分之90以上,当然我们还可以修改线程常量进行线程控制。

下面我们将对上面线程参数进行一一讲解:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) 

corePoolSize : 每秒需要多少个线程处理? 
threadcount = tasks/(1/taskcost) =tasks*taskcout =  (100~1000)*0.1 = 10~100 个线程。corePoolSize设置应该大于10
根据8020原则,如果80%的每秒任务数小于200,那么corePoolSize设置为20即可
 

maximumPoolSize:最大线程数量,当前线程池最大接收线程数量,如果超出的话超出的线程将进行等待或者不执行销毁。

keepAliveTime : 表示线程的存活时间,举例:一个工地设置了20个人(最大线程数),当工地活干完了有10个人处于空闲时间,当空闲时间达到了我们设定的时间就进行辞退(销毁)。

unit : 线程存活时间单位。

workQueue:工作队列(阻塞队列)选择,线程池中常用的阻塞队列有三种

BlockingQueue workQueue = null;
workQueue = new SynchronousQueue<>();//无缓冲的等待队列
workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列
workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列

SynchronousQueue是一个不存储元素的阻塞队列,适合传递性场景,只是负责把父线程提交的任务直接交给线程池线程处理。也就是说提交的任务数超过最大线程数就会执行拒绝策略

ArrayBlockingQueue底层是用数组实现的有界阻塞队列,因为需要传初始值(如果传Integer最大值,也类似于无界了)。队列按照先进先出的原则对元素进行排序

LinkedBlockingQueue底层是用链表实现的有界阻塞队列,如果不传初始化值为Integer最大值,也是先进先出对元素进行排序

一般选择建议选择有界队列,因为如果任务特别多,核心线程处理不过来,会将任务都放到工作队列中,此时最大线程数已经没有意义了。如果控制不好会导致OOM

handler :最后一个就是拒绝策略选择,JDK提供了四种拒绝策略
AbortPolicy:直接丢弃新任务,抛出异常,当有多个任务时,只要任务超出了设定任务的最大线程数加阻塞数时,就会抛出异常,没有超出的线程正常执行,超出报异常后面的不执行。

new ThreadPoolExecutor(
                ThreadPoolConstant.CORE_THREAD_NUM
                , ThreadPoolConstant.MAX_THREAD_NUM,
                ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(ThreadPoolConstant.QUEUE_LENGTH),Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.AbortPolicy());

DiscardPolicy:直接丢弃掉,不会抛出异常,最大线程数加阻塞数如果只要10,那么前10个线程会正常执行,后面加入的线程会被丢弃。

new ThreadPoolExecutor(
                ThreadPoolConstant.CORE_THREAD_NUM
                , ThreadPoolConstant.MAX_THREAD_NUM,
                ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(ThreadPoolConstant.QUEUE_LENGTH),Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.DiscardPolicy());


DiscardOldestPolicy:丢弃时间最久的任务。一般是队列最前面的任务,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入到阻塞队列中

new ThreadPoolExecutor(
                ThreadPoolConstant.CORE_THREAD_NUM
                , ThreadPoolConstant.MAX_THREAD_NUM,
                ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(ThreadPoolConstant.QUEUE_LENGTH),Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.DiscardOldestPolicy());


CallerRunsPolicy:交给主线程去执行,多余的任务会被放入队列中,最后的任务还是继续被执行。

new ThreadPoolExecutor(
                ThreadPoolConstant.CORE_THREAD_NUM
                , ThreadPoolConstant.MAX_THREAD_NUM,
                ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(ThreadPoolConstant.QUEUE_LENGTH),Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.CallerRunsPolicy());

4种拒绝策略,给大家提供一个非常详细讲解的地址

Java 线程池四种拒绝策略_小码code的博客-CSDN博客_线程池的拒绝策略

你可能感兴趣的:(java,多线程,线程池,java,开发语言)