Android 中线程池的使用

2,092 阅读5分钟

本文来自:Amit Shekhar的一篇译文,地址
medium.freecodecamp.com/threadpoole…

本文主要讲解线程池、线程池Executor在Android的使用,并且通过代码片段来覆盖这些主题。
这里写图片描述

线程池(主要包含线程池和任务队列)

.线程池管理一池的工作线程(最终数量还得依赖线程池的具体实现)。

.任务队列存放等待被线程池中的空闲线程处理的任务,一旦有后台有新的任务等待空闲线程处理的时候那么空闲线程就类似于”消费者”不断的消费将任务加入到队列的”生产者”。

ThreadPoolExecutor(线程池执行者)

.ThreadPoolExecutor执行一个给定的任务使用一个线程池的线程。
一个典型的初始化例子。

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
);

参数的含义解释:
1.corePoolSize: 线程池中线程的最小数量,默认情况下线程池中的线程数量为0。随着任务加入队列中,新的线程就会被创建。如果线程池中存在空闲线程但是线程总数小于corePoolSize那么仍然会继续创建新的线程。
2.maximumPoolSize:线程池中允许存在的最大线程总数。如果线程总数>=corePoolSize那么新的线程还会继续被创建直到队列满了。
3.keepAliveTime: 如果线程数大于核心线程数量即corePoolSize时,非核心线程(即额外的空闲线程)将等待新来的任务,如果在我们定义的时间内未能接收到新的任务,那么该线程将被终止。
4.unit: keepAliveTime的时间单位。
5.workQueue: 任务队列,用于存放Runanable任务,它必须是一个BlockingQueue

为什么要在Android或者Java应用中使用Thread Pool Executor

1.Thread Pool Executor本身是一个非常优秀的框架,支持存放任务,取消任务,给任务配置优先级。
2.它减小了所需要创建的线程的最大数量,因为它维护了指定数量的线程在它的池子中,能减少不少线程带来的开支。

在Android中使用ThreadPoolExecutor

首先,创建一个PriorityThreadFactory:

public class PriorityThreadFactory implements ThreadFactory {

    private final int mThreadPriority;

    public PriorityThreadFactory(int threadPriority) {
        mThreadPriority = threadPriority;
    }

    @Override
    public Thread newThread(final Runnable runnable) {
        Runnable wrapperRunnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Process.setThreadPriority(mThreadPriority);
                } catch (Throwable t) {

                }
                runnable.run();
            }
        };
        return new Thread(wrapperRunnable);
    }
}

创建一个MainThreadExecutor:

public class MainThreadExecutor implements Executor {

    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void execute(Runnable runnable) {
        handler.post(runnable);
    }
}

创建一个DefaultExecutorSupplier:

/*
* 一个executor单例
*/
public class DefaultExecutorSupplier{
    /*
    * 核心线程数量
    */
    public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

    /*
    * 后台任务Executor
    */
    private final ThreadPoolExecutor mForBackgroundTasks;
    /*
    * 轻量级后台任务Executor
    */
    private final ThreadPoolExecutor mForLightWeightBackgroundTasks;
    /*
    * 主线程任务Executor
    */
    private final Executor mMainThreadExecutor;
    /*
    * DefaultExecutorSupplier单例对象
    */
    private static DefaultExecutorSupplier sInstance;

    /*
    * 返回一个DefaultExecutorSupplier单例
    */
    public static DefaultExecutorSupplier getInstance() {
       if (sInstance == null) {
         synchronized(DefaultExecutorSupplier.class){                                                                  
             sInstance = new DefaultExecutorSupplier();      
        }
        return sInstance;
    }

    /*
    * DefaultExecutorSupplier构造函数
    */ 
    private DefaultExecutorSupplier() {

        // 设置线程工厂对象
        ThreadFactory backgroundPriorityThreadFactory = new 
                PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);

        // 初始化mForBackgroundTasks
        mForBackgroundTasks = new ThreadPoolExecutor(
                NUMBER_OF_CORES * 2,
                NUMBER_OF_CORES * 2,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(),
                backgroundPriorityThreadFactory
        );

        // 初始化mForLightWeightBackgroundTasks
        mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
                NUMBER_OF_CORES * 2,
                NUMBER_OF_CORES * 2,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(),
                backgroundPriorityThreadFactory
        );

        // 初始化mMainThreadExecutor
        mMainThreadExecutor = new MainThreadExecutor();
    }

    /*
    * 返回后台任务Executor
    */
    public ThreadPoolExecutor forBackgroundTasks() {
        return mForBackgroundTasks;
    }

    /*
    * 返回轻量级的Executor
    */
    public ThreadPoolExecutor forLightWeightBackgroundTasks() {
        return mForLightWeightBackgroundTasks;
    }

    /*
    * 返回主线程Executor
    */
    public Executor forMainThreadTasks() {
        return mMainThreadExecutor;
    }
}

ps:可用线程数量会因不同设备而返回不同的数量。

现在我们就可以在代码中愉快的使用了:

/*
* 用于执行后台任务
*/
public void doSomeBackgroundWork(){
  DefaultExecutorSupplier.getInstance().forBackgroundTasks()
    .execute(new Runnable() {
    @Override
    public void run() {
       // do some background work here.
    }
  });
}

/*
* 用于执行轻量级任务
*/
public void doSomeLightWeightBackgroundWork(){
  DefaultExecutorSupplier.getInstance().forLightWeightBackgroundTasks()
    .execute(new Runnable() {
    @Override
    public void run() {
       // do some light-weight background work here.
    }
  });
}

/*
* 用于执行主线程任务
*/
public void doSomeMainThreadWork(){
  DefaultExecutorSupplier.getInstance().forMainThreadTasks()
    .execute(new Runnable() {
    @Override
    public void run() {
       // do some Main Thread work here.
    }
  });
}

这样,我们就能创建一个线程池用于执行网络任务、I/O任务、繁重的后台任务、等等任务。

如何取消一个任务?

为了取消一个任务,我们必须得到future对象。所以我们需要使用submit来代替execute来提交任务,这样我们就能得到一个future,然后就可以取消一个任务了。

/*
* 得到提交到线程池的future对象
*/
Future future = DefaultExecutorSupplier.getInstance().forBackgroundTasks()
    .submit(new Runnable() {
    @Override
    public void run() {
      // do some background work here.
    }
});

/*
* 取消该任务
*/
future.cancel(true); 

如何为任务设置优先级?

假如我们有20条任务在队列中,但是线程池只有4条线程看用于执行。我们通过优先级来执行任务,毕竟最多只能并发执行4个任务。
再假如我们想把最后加入队列的任务优先执行,那么我们不得不给它设置IMMEDIATE优先级,让他优先执行(因为它的优先级最高)。

为了给任务设置优先级,我们需要重新创建一个Executor:
首先,创建一个优先级ENUM:

/**
 * 优先等级
 */
public enum Priority {
    /**
     * NOTE: 不允许修改这些常量的顺序.
     * 为了确保能按正确的顺序执行.
     */

    /**
     * 低等级. 用于读取数据
     */
    LOW,

    /**
     * 中等级,用于很快就能获取到数据
     */
    MEDIUM,

    /**
     * 高等级. 用于几乎马上就能得到数据
     */
    HIGH,

    /**
     * 高等级,用于能立即得到数据
     */
    IMMEDIATE;

}

创建PriorityRunnable:

public class PriorityRunnable implements Runnable {

    private final Priority priority;

    public PriorityRunnable(Priority priority) {
        this.priority = priority;
    }

    @Override
    public void run() {
      // nothing to do here.
    }

    public Priority getPriority() {
        return priority;
    }

}

创建一个PriorityThreadPoolExecutor extends ThreadPoolExecutor,创建一个PriorityFutureTask implement Comparable< PriorityFutureTask >:

public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {

   public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
         TimeUnit unit, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit,new PriorityBlockingQueue<Runnable>(), threadFactory);
    }

    @Override
    public Future<?> submit(Runnable task) {
        PriorityFutureTask futureTask = new PriorityFutureTask((PriorityRunnable) task);
        execute(futureTask);
        return futureTask;
    }

    private static final class PriorityFutureTask extends FutureTask<PriorityRunnable>
            implements Comparable<PriorityFutureTask> {
        private final PriorityRunnable priorityRunnable;

        public PriorityFutureTask(PriorityRunnable priorityRunnable) {
            super(priorityRunnable, null);
            this.priorityRunnable = priorityRunnable;
        }

        /*
         * compareTo() method is defined in interface java.lang.Comparable and it is used
         * to implement natural sorting on java classes. natural sorting means the the sort 
         * order which naturally applies on object e.g. lexical order for String, numeric 
         * order for Integer or Sorting employee by there ID etc. most of the java core 
         * classes including String and Integer implements CompareTo() method and provide
         * natural sorting.
         */
        @Override
        public int compareTo(PriorityFutureTask other) {
            Priority p1 = priorityRunnable.getPriority();
            Priority p2 = other.priorityRunnable.getPriority();
            return p2.ordinal() - p1.ordinal();
        }
    }
}

最后,在DefaultExecutorSupplier中用PriorityThreadPoolExecutor替换掉ThreadPoolExecutor:

public class DefaultExecutorSupplier{

private final PriorityThreadPoolExecutor mForBackgroundTasks;

private DefaultExecutorSupplier() {

        mForBackgroundTasks = new PriorityThreadPoolExecutor(
                NUMBER_OF_CORES * 2,
                NUMBER_OF_CORES * 2,
                60L,
                TimeUnit.SECONDS,
                backgroundPriorityThreadFactory
        );

    }
}

举个例子,如何设置高等级的任务:

/*
* do some task at high priority
*/
public void doSomeTaskAtHighPriority(){
  DefaultExecutorSupplier.getInstance().forBackgroundTasks()
    .submit(new PriorityRunnable(Priority.HIGH) {
    @Override
    public void run() {
      // do some background work here at high priority.
    }
});
}

这样一个任务就可以优先被执行了。

我希望这些讲解能对你有帮助。