Java中的线程池

线程池的好处

  • 降低资源消耗,避免线程频繁创建和销毁,避免无线创建线程,统一管理线程,通过线程池可以设置核心线程池数量,统一分配线程等,达到线程复用的目的。可以进行线程监控,提高响应速度,减少了创建线程和销毁线程的时间,响应速度就自然提高了

线程池处理流程

image-20200715143309338

  • 如果核心线程池和队列已满,创建线程执行任务,是需要获取全局锁的,所以上述步骤的总体思路是为了尽可能避免获取全局锁

  • 线程池在创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,会循环获取工作队列里的任务来执行。

  • 预热阶段指当前线程<=corePoolSize

线程池的核心参数

  • corePoolSize

  • maximumPoolSize

  • KeepAliveTime:多余空闲线程存活时间,当前线程池的数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。

  • TimeUnit:存活时间单位

  • RejectedExecutionHandler:饱和策略

  • runnableTaskQueue:任务队列

  • ThreadFactory:表示生成线程池中线程的线程工厂,用于创建线程,一般用默认的即可,可以设置创建的线程的名字

  • 四种饱和策略:

    AbortPolicy : 始终抛出RejectedExecutionException

    CallerRunsPolicy : 如果线程池未关闭,则交给调用线程池的线程执行

    DiscardPolicy :不处理,丢弃掉

    DiscardOldestPolicy : 丢弃队列里最老的任务,然后将当前这个任务重新提交给线程池。

    也可以实现RejectedExecutionHandler接口自定义策略

线程池的五种状态

img

excute方法

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 1. 如果工作线程数小于核心线程数(corePoolSize),则创建一个工作线程执行任务
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }

    // 2. 如果当前是running状态,并且任务队列能够添加任务
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 2.1 如果不处于running状态了(使用者可能调用了shutdown方法),则将刚才添加到任务队列的任务移除
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 2.2 如果当前没有工作线程,则新建一个工作线程来执行任务(任务已经被添加到了任务队列)
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }

  // 3. 队列已经满了的情况下,则新启动一个工作线程来执行任务
    else if (!addWorker(command, false))
        reject(command);
}

向线程池提交任务

  • execute()

用于提交不需要返回值的任务,无法判断任务是否完成

  • submit()

用于提交需要返回值的任务,线程池会返回一个future类型的对象

通过这个future对象可以判断任务是否成功,用future.get()方法会阻塞当前线程直到任务完成,也可以用get(long timeout,TimeUnit unit) 设置阻塞时间

关闭线程池

可以调用线程池的shutdown或者shutdownNow,都是调用线程的interrupt方法中断线程

shutdownNow线程池状态设置为stop,正在执行的任务不一定会执行完,如果shutdown,会把线程池状态设置为shutdown,然后中断所有没有正在执行任务的线程。调用了两种方法其中一种,isShutdown方法会返回true,而所有任务都已关闭后,才表示线程池关闭成功,这时候调用isTerminated方法会返回true

合理配置线程池

根据任务特性,配置线程池,

是CPU密集型任务,还是IO密集型任务,还是混合型,或者说是需要优先级?

CPU密集型应该配置尽可能小的线程,如N+1,N为CPU核数,IO密集型任务可以配置尽可能多的线程,如2*N,混合型,可以进行拆分,看哪个部分占比大,优先级不同的可以使用优先级队列。

(优先级队列,可能会导致低优先级的任务一直得不到执行)

建议任务队列使用有界队列

如果核心线程池满了,无界队列会导致任务一直排队,最后可能会撑爆内存,导致系统崩溃

线程池监控

taskCount:线程池需要执行的任务数量

completedTaskCount:已经完成的任务数量,小于等于taskCount

largestPoolSize:线程池里创建过的最大的线程数量,通过这个数据可以知道线程池是否瞒过

getPoolSize:获得线程池的数量

getActiveCount:获取活动的线程数

任务数量,小于等于taskCount

largestPoolSize:线程池里创建过的最大的线程数量,通过这个数据可以知道线程池是否瞒过

getPoolSize:获得线程池的数量

getActiveCount:获取活动的线程数

还可以使用aop思想,在任务执行前任务执行后,和线程池关闭时,写入一些代码进行监控,比如统计任务执行时间,通过重写beforeExecute、afterExecute、terminated方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值