Advertisement

安卓开发中我们应该使用 Java 线程池还是 HandlerThread 线程池?

阅读量:

上篇详细说明了一下安卓线程类的机理和使用方法。今天来聊聊 Java 线程池的创建和管理,以及什么时候我们需要创建线程池,什么时候使用安卓sdk提供的线程类和我们需不需要单独为 HandlerThread 创建一个线程池管理类。


先简单聊一下 Java 中建立线程池的 helper 类:ThreadPoolExector,通过直接配置相关的参数就可以简单使用将县城的管理全权委托给内部的实现。

复制代码
    public class myThreadManager {
    private static final int POOLSIZE = 5;
    private static final int MAXPOOLSIZE = 7;
    private static final long KEEPALIVETIME = 1;
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(POOLSIZE,
            MAXPOOLSIZE,
            KEEPALIVETIME,
            TimeUnit.HOURS,
            new LinkedBlockingQueue<Runnable>());
    
    
    public void execute(Runnable command) {
        threadPool.execute(command);
    }
    
    public Future<?> post(Callable<?> task) {
        return threadPool.submit(task);
    }
    
    public void destroy() {
        threadPool.shutdown();
    }
    }

可配置的参数有 corePoolSize (第一个参数)以及 maxPoolSize,其中 corePoolSize 是这个线程池固体保持的最小线程数,如果执行任务的线程数小于 corePoolSize 且当前所有线程被占用时,新的任务进来会开启一个新的线程直到当前总线程数达到 corePoolSize。之后线程池会的线程数不会小于 corePoolSize,而 maxPoolSize - corePoolSize 之间的线程是动态管理的,根据第三个参数 keepAliveTime 来决定其存活时间,当该线程在这个时间内都没有执行任何的任务则会被销毁回收,上面这个例子是一个小时。
另外我们还可以配置队列类型和线程工厂类,这个队列用于分发任务给不同的线程,它有几种相应的策略:

  1. 不保存直接分发任务给空的线程,如果所有线程被占满且无法开新的线程则会拒绝该任务,这种队列隐含着一层条件,即该线程池的线程数是足够大的,否则很多任务可能会失败。这个策略避免了互相有依赖的线程导致的死锁问题,同时对处理任务的速率有一个明显的控制。

  2. 优先保存任务,该策略在线程数达到 corePoolSize 后不再开辟新的线程,总是将任务
    加入队列。这种策略适用于任务之间都是独立不受影响的。

  3. 择中控制,队列的大小和最大线程数相互制约,好的匹配可以使任务吞吐量较高的同时CPU也最大化利用,缺点是难以控制对应值的大小,需要不断实践。

线程工厂类可以自定义线程相关的属性包含其优先级(非常重要),默认都是 Normal Priority,无法体现任务之间的优先级关系。这个在创建 handlerThread 时也同样可以修改,统一由进程控制。

那么回到最初的问题,我们什么时候用 Java 提供的线程池呢?

首先安卓提供的 HandlerThread 是长连接的,我们想真正同时运行多个任务就需要创建多个 HandlerThread, 我们不需要这么多线程时就需要将它销毁,所以我们需要一个线程池的概念来帮助我们“自动“管理这些线程,但每个 HandlerThread 都包含一个内置的队列和 Looper 销毁和创建的成本都明显高于 Thread,执行额外的临时任务就不需要建一个 HandlerThread 然后再将它销毁而是建一个 Thread 来执行,执行完毕就回收它。当程序内这种额外的临时任务数量可预见的较多时,用 Java 的线程池最合适不过。提高了资源的利用率也避免了线程不断创建销毁的 over-head 时间。

我们需要创建关于 HandlerThread 的线程池吗?

先给答案–不需要。本质是因为 HandlerThread 的设计就是 keep-alive 的,创建出来就应该有个独特的名字和使命,分别去处理哪些独特的任务,相互之间的通信也比较简单,通过名字去发送消息的方式清晰易懂,当然如果创建的 HandlerThread 较多,也可以设计一个管理类去提供引用和任务分发,但大多数情况是不需要的,即用即抛的额外任务还是交给 Thread 来处理吧,为笨重的安卓应用减减负。

全部评论 (0)

还没有任何评论哟~