Android中线程池的使用分析

作者: 程序员指北 | 来源:发表于2017-06-16 11:34 被阅读55次

    引言:
    说起线程池,学习过Java基础的同学估计都不陌生,Android中的线程池其实就是java的线程池。那么为什么线程池名声这么大,当然有其独特之处。这就引来了线程池到底有何优势。
    线程池的优势:
    Android中像访问内存卡,联网等耗时较长的任务时,需要在异步线程中进行,所以需要新开线程进行。但创建或者销毁线程伴随着系统的开销,频繁的创建和销毁线程,会较大的影响系统的性能。使用线程池,可用已有的闲置线程来执行新任务。
    我们知道线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况,运用线程池能有效的控制线程最大并发数,避免以上的问题。
    线程池能够对线程进行有效的管理,比如延时执行,定时定周期循环执行等。

    线程池ThreadPoolExecutor
    既然线程池有这些优势,那么我们就要考虑怎样使用它。还是那句话,一个有追求的青年,要追根溯源。
    android中的线程池来源于java中的线程池,那么我们就分析一下:
    java中线程池的概念是一个接口,Excutor;其中ThreadPoolExecutor是这个接口的具体实现,也就是说线程池的所有定义及大部分操作将会从这个ThreadPoolExecutor中进行逻辑处理。那么我们就去看一下ThreadPoolExecutor的具体实现。
    ThreadPoolExecutor的四个构造函数:

    // 第一种构造器
    public ThreadPoolExecutor(int corePoolSize, 
                            int maximumPoolSize, 
                            long keepAliveTime, 
                            TimeUnit unit,
                         BlockingQueue<Runnable> workQueue) {
        throw new RuntimeException("Stub!");
    }
    
    // 第二种构造器
    public ThreadPoolExecutor(int corePoolSize, 
                            int maximumPoolSize, 
                            long keepAliveTime,
                         TimeUnit unit, 
                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        throw new RuntimeException("Stub!");
    }
    
    // 第三种构造器
    public ThreadPoolExecutor(int corePoolSize, 
                            int maximumPoolSize, 
                            long keepAliveTime, 
                            TimeUnit unit, 
                            BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        throw new RuntimeException("Stub!");
    }
    
    // 第四种构造器
    public ThreadPoolExecutor(int corePoolSize, 
                            int maximumPoolSize, 
                            long keepAliveTime, 
                            TimeUnit unit, 
                            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        throw new RuntimeException("Stub!");
    }
    

    看到这些构造函数的参数是不是一脸懵逼,不要急不要慌,其实搞明白第一种构造函数就可以了其他三个都是鸡肋。下面我们就详细的分析一下这些参数。

    1. corePoolSize:核心线程数 线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程;核心线程会一直保留,即使处于空闲状态,要想隔一段时间销毁它,必须指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true。

    2. maximumPoolSize:线程池中线程的最大数 最大数 = 核心线程数 + 非核心线程数;其中非核心线程就是在线程池中的核心线程已满,但线程总数小于最大数时创建的线程为费核心线程。

    3. keepAliveTime: 非核心线程保留时长 当非核心线程空闲时间超过保留时长时,就会被销毁掉。

    4. TimeUnit:keepAliveTime的单位,TimeUnit是一个枚举类型

    public enum TimeUnit { 
              DAYS, 
              HOURS, 
              MICROSECONDS,
              MILLISECONDS, 
              MINUTES, 
              NANOSECONDS,
              SECONDS; }
    

    5 BlockingQueue 线程池中的任务队列:维护着等待执行的Runnable对象;当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。
    其他的两个参数基本不用,需要详细了解的可以自行查看源码。

    ThreadPoolExecutor的具体使用

    认识完ThreadPoolExecutor,接下来就看一下怎样使用。其实很简单;

    ① new ThreadPoolExecutor对象,参数自行配置
    ② 使用对象调用execute方法,方法里传入runnable接口
    ③ 上②的runnable接口就是需要执行的任务
    

    经过上面三步就完成了一个任务的添加执行。

    常见的四种线程池对象

    我们牛逼的Google攻城狮给我们封装了四种常用的线程池对象,就是对ThreadPoolExecutor进行不同参数进行详细配置的具体实现。当然我们也可以按照上述三步走进行自定义ThreadPoolExecutor线程池。但一般情况这四种线程池足够我们使用。

    CachedThreadPool(): 直接从源码中寻找答案:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                60L, TimeUnit.SECONDS, 
                        new SynchronousQueue<Runnable>());
    }
    

    从上述源码可以看出可缓存线程池的特点:
    ① 线程数无限制
    ② 没有核心线程,都是非核心线程

    使用方法:

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    

    2 . FixedThreadPool():定长线程池
    源码:

    public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                      0L,TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
    }
    

    特点:①:可控制线程最大并发数(线程数固定)
    ②:超出的线程会在队列中等待

    使用方法:

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);
    

    3 . ScheduledThreadPool():定时和周期性线程池

    4 . SingleThreadExecutor():单一线程池
    ① 有且仅有一个工作线程执行任务
    ② 所有任务按照指定顺序执行,即遵循队列的入队出队规则

    感谢
    关于线程池的这篇文章参考(_liuzh)和(SEU_Calvin)的博客,感谢他们无私的分享。
    ———————————END BUT FINAL——————————-

    相关文章

      网友评论

        本文标题:Android中线程池的使用分析

        本文链接:https://www.haomeiwen.com/subject/atgpqxtx.html