Java并发编程 - 线程池

线程池是一种生产者/消费者模式的实现.

线程池处理任务的流程

ThreadPoolExecutor是一种线程池的实现, 它执行execute()的处理流程如下:

threadpoolexecutor-process

上图中与新创建线程有关的步骤都需要获取全局锁, 所以线程池中应当尽量避免进行新线程的创建.
实际上在ThreadPoolExecutor完成预热之后(corePoolSize已满)的时候, 几乎所有的execute()方法都是执行入队操作.
这样就避免了全局锁的获取(注意: 并不是说入队不需要获取锁, 只是这时候获取的不是全局锁而已).

线程池的使用

线程池的创建

可以通过ThreadPoolExecutor来创建一个线程池:

new ThreadPoolExecutor(
    corePoolSize, // 线程池的基本大小, 小于此数值时仅新建线程
    maximumPoolSize, 
    keepAliveTime, // 线程池的工作线程空闲时, 保持存活的时间.
    milliseconds, 
    runnableTaskQueue, // 任务队列, 需要使用阻塞队列
    handler); // 当线程池和队列都满了的时候的丢弃策略

向线程池提交任务

两种方法:

  1. 使用execute(), 适用于提交不需要返回值的任务, 所以也无法判断任务是否被线程池执行成功;

    threadPool.execute(new Runnable() {
        @override
        public void run() {
            // 这里是具体的代码
        }
    });
    
  2. 使用submit(), 适用于提交需要返回值的任务, 会返回一个Future类型的对象, 用于判断任务是否执行成功.
    可以通过Future对象的get()方法来获取返回值. get()会阻塞当前线程直到任务完成.

    Future<Object> future = threadPool.execute(hasReturnValueTask);
    try {
        Object o = future.get();
    } catch(Exception e) {
    } finally {
        threadPool.shutdown();
    }
    

关闭线程池

通常调用shutdown()方法来关闭线程池, 确保所有正在执行的任务都正常完成;

如果当前任务不一定要执行完, 也可以使用shutdownNow()来进行.

合理的配置线程池

以下以CPU的总核心数为n来计算

核心线程数

需要根据任务的性质来具体划分

  • 如果是计算密集型任务(也就是CPU密集型任务, 大量快速执行的小任务), 则配置n+1个线程, 充分利用CPU的计算能力.
  • 如果是IO密集型任务, 则单任务的等待时间长, 则应该配置尽可能多的线程, 比如2*n
  • 如果是混合型的任务, 则可以配置两个不同规模的线程池, 也可以使用优先级队列, 让执行时间短的任务先执行;

队列的选择

可以使用优先级队列PriorityBlockingQueue来处理, 让优先级高的任务先执行.

另外, 建议使用有界队列, 因为在遇到IO问题时, 有界队列只会发出抛弃任务的异常,
但如果使用了无界队列, 则有可能不断创建线程, 最终导致内存溢出, 影响其他线程.

线程池的监控

监控线程池的运作方便在出现问题时, 可以根据线程池的使用状况快速定位问题, 也有利于进行调优.
在监控线程池的时候有如下属性:

  • taskCount: 需要执行的任务量;
  • completedTaskCount: 已完成的任务量, 小于等于taskCount;
  • largestPoolSize: 池中的历史最大线程数量, 可以据此判断线程池是否满过, 也就是是否用过队列;
  • getPoolSize: 得到线程池的当前线程数量, 只增不减的一个值.
  • getActiveCount: 获取活动的线程数;

要使用以上属性, 需要创建线程池实现类的子类, 并重写beforeExecute, afterExecute, terminated方法.
例如: 监控任务的平均执行时间, 最大执行时间, 最小执行时间等.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值