Java线程池小结

线程池参数

参数名作用
corePoolSize核心线程数
maximumPoolSize最大线程数
keepAliveTime线程池中超过corePoolSize数目的空闲线程最大存活时间;当设置allowCoreThreadTimeOut=true会使得核心线程也超时被释放
TimeUnitkeepAliveTime时间单位
workQueue阻塞任务队列
threadFactory新建线程的工厂
rejectedExecutionHandler当提交任务数超过maxmumPoolSize + workQueue之和时,任务会交给rejectedExecutionHandler来处理
allowCoreThreadTimeout默认为false,设置为true时,当core thread超过过期时间时也会被释放

如何设置参数

默认值

corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExecutionHandler=AbortPolicy()

参考值

QPS :每秒的任务数,假设为500~1000
cost_time :每个任务花费时间,假设为0.1s
max_response_time :系统允许容忍的最大响应时间,假设为1s
max_capacity :每秒系统能够支撑当最大容量(通常是DB/IO/CPU资源限制)

得出数据

corePoolSize = 每秒需要多少个线程处理?
threadcount = QPS / ( 1s/cost_time ) = QPS * cost_time =  (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50
根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可

queueCapacity = (corePoolSize / cost_time) * max_response_time
计算可得 queueCapacity = 80/0.1 * 1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行
切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。

最大线程数 = (最大任务数-队列容量)/每个线程每秒处理能力
maxPoolSize = (min(max(QPS),max_capacity)- queueCapacity) / (1s/cost_time)
计算可得 maxPoolSize = (1000-80)/10 = 92

rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
keepAliveTime和allowCoreThreadTimeout采用默认通常能满足

问题

Q: 为什么不直接将队列大小设小一点呢,这样就能直接创建线程处理任务了?

A: 直觉上来说是这样的,但是任务类型分为CPU密集型和IO密集型。如果是CPU密集型任务,那么CPU将会是瓶颈,创建过多线程反而会适得其反,因为在CPU的维度上,每次同时执行任务的数量与核数成正比,如果线程数过多,那么线程上下文切换的时间消耗将会增加,反而造成处理效率的低下。如果是IO密集型,那么可以适当的增加corePoolSize。

扩展

ThreadPoolExecutor扩展点

#在任务执行之前执行
beforeExecute(java.lang.Thread,java.lang.Runnable)
#在任务完成之后执行
afterExecute(java.lang.Runnable,java.lang.Throwable)
#当线程池被关闭时执行
terminated()

一个参考(记录任务执行的时间)

private ThreadLocal<Long> taskExecuteStart = new ThreadLocal<>();

@Override
protected void beforeExecute(Thread t, Runnable r) {
    taskExecuteStart.set(System.currentTimeMillis());
}

@Override
protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    Long start = taskExecuteStart.get();
    Long executeTime = System.currentTimeMillis() - start;
    //记录执行时间
    taskExecuteStart.remove();
}

@Override
protected void terminated() {
    //记录日志和监控
}

ThreadFactory扩展点

public interface ThreadFactory {

    /**
     * Constructs a new {@code Thread}.  Implementations may also initialize
     * priority, name, daemon status, {@code ThreadGroup}, etc.
     *
     * @param r a runnable to be executed by new thread instance
     * @return constructed thread, or {@code null} if the request to
     *         create a thread is rejected
     */
    Thread newThread(Runnable r);
}

ThreadFactory主要用于创建线程,因此我们可以通过Thread来扩展某些功能,比如catch异常,为线程设置名字,设置线程执行优先级等等。

一个参考(设置线程名字,以及设置默认异常catch)

class NamedThreadFactory implements ThreadFactory {
    private final AtomicInteger mThreadNum;
    private final String mPrefix;
    private final boolean mDaemo;
    private final ThreadGroup mGroup;

    public NamedThreadFactory(String prefix) {
        this(prefix, true);
    }

    public NamedThreadFactory(String prefix, boolean daemo) {
        this.mThreadNum = new AtomicInteger(1);
        this.mPrefix = prefix + "-thread-";
        this.mDaemo = daemo;
        SecurityManager s = System.getSecurityManager();
        this.mGroup = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
    }

    public Thread newThread(Runnable runnable) {
        String name = this.mPrefix + this.mThreadNum.getAndIncrement();
        Thread ret = new Thread(this.mGroup, runnable, name, 0L);
        ret.setUncaughtExceptionHandler(DefaultUncaughtExceptionHandler.INSTANCE);
        ret.setDaemon(this.mDaemo);
        return ret;
    }

    public ThreadGroup getThreadGroup() {
        return this.mGroup;
    }
}

enum DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    INSTANCE;

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        //记录日志和监控
    }
}

参考

https://blog.csdn.net/java1993666/article/details/71272559

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值