在android中使用ThreadPoolExector

本篇文章主要介绍线程池,线程池executors及它们在android中的使用。我将使用一些例子代码来进行讲解。

Thread Pools

线程池管理着一些工作线程(实际的线程数取决于具体的实现)。

任务队列(task queue)持有一些任务,这些任务等待着被线程池中的空闲线程执行。任务被生产者加入到任务队列中。工作线程(worker threads)扮演着消费者的角色。当一个空闲线程准备完毕将会从任务队列中取出一个任务在后台进行执行。

ThreadPoolExecutor

ThreadPoolExecutor使用线程池中的线程执行给定的任务

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

这些参数都是什么意思?

  1. corePoolSize:线程池中维持的线程的最低数量。初始值为0,当有新的任务被加入到队列中的时候,新的线程将被创建。假如线程池中存在空闲线程,但是线程的数量低于corePoolSize这时新的线程将会被创建。
  2. maximumPoolSize:线程池中所能维持的线程的最大数量。假如其值大于corePoolSize并且当前线程的数量大于或等于corePoolSize且当前的队列是满的情况下新的工作线程将被创建。
  3. keepAliveTime:当线程池中的线程数大于处理任务所需的线程数的时候,多余的空闲线程将会等待新的任务,假如在keepAliveTime参数定义的时间内没有新任务被分配到空闲线程,空闲的线程将会被终止。
  4. unit: keepAliveTime参数的时间单位
  5. workQueue:任务队列,它只持有可运行的任务,必须是BlockingQueue

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

  1. 它是一个强大的任务执行框架,支持添加任务到队列,任务撤消和任务优先级。
  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


/*
* Singleton class for default executor supplier
*/
public class DefaultExecutorSupplier{
    /*
    * Number of cores to decide the number of threads
    */
    public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

    /*
    * thread pool executor for background tasks
    */
    private final ThreadPoolExecutor mForBackgroundTasks;

    /*
    * thread pool executor for light weight background tasks
    */
    private final ThreadPoolExecutor mForLightWeightBackgroundTasks;

    /*
    * thread pool executor for main thread tasks
    */
    private final Executor mMainThreadExecutor;

    /*
    * an instance of DefaultExecutorSupplier
    */
    private static DefaultExecutorSupplier sInstance;

    /*
    * returns the instance of DefaultExecutorSupplier
    */
    public static DefaultExecutorSupplier getInstance() {
        if (sInstance == null) {
            synchronized(DefaultExecutorSupplier.class){
                sInstance = new DefaultExecutorSupplier();
        }
        return sInstance;
    }

    /*
    * constructor for DefaultExecutorSupplier
    */ 
    private DefaultExecutorSupplier() {
        // setting the thread factory
        ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
        // setting the thread pool executor for mForBackgroundTasks;
        mForBackgroundTasks = new ThreadPoolExecutor(
                NUMBER_OF_CORES * 2,
                NUMBER_OF_CORES * 2,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(),
                backgroundPriorityThreadFactory
        );

        // setting the thread pool executor for mForLightWeightBackgroundTasks;
        mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
                 NUMBER_OF_CORES * 2,
                 NUMBER_OF_CORES * 2,
                 60L,
                 TimeUnit.SECONDS,
                 new LinkedBlockingQueue(),
                 backgroundPriorityThreadFactory
        );

        // setting the thread pool executor for mMainThreadExecutor;
        mMainThreadExecutor = new MainThreadExecutor();
    }

    /*
    * returns the thread pool executor for background task
    */
    public ThreadPoolExecutor forBackgroundTasks() {
        return mForBackgroundTasks;
    }

    /*
    * returns the thread pool executor for light weight background task
    */

    public ThreadPoolExecutor forLightWeightBackgroundTasks() {
        return mForLightWeightBackgroundTasks;
    }

    /*
    * returns the thread pool executor for main thread task
    */
    public Executor forMainThreadTasks() {
        return mMainThreadExecutor;
    }
}

注意:不同的线程池中所需的线程数取决于你需求

像下面一样在你的代码中使用它

/*
* Using it for Background Tasks
*/
public void doSomeBackgroundWork(){
    DefaultExecutorSupplier.getInstance().forBackgroundTasks()
        .execute(new Runnable() {
        @Override
        public void run() {
            // do some background work here.
        }
    });
}

/*
* Using it for Light-Weight Background Tasks
*/
public void doSomeLightWeightBackgroundWork(){
    DefaultExecutorSupplier.getInstance().forLightWeightBackgroundTasks()
        .execute(new Runnable() {
        @Override
        public void run() {
            // do some light-weight background work here.
        }
    });
}

/*
* Using it for MainThread Tasks
*/
public void doSomeMainThreadWork(){
    DefaultExecutorSupplier.getInstance().forMainThreadTasks()
        .execute(new Runnable() {
        @Override
        public void run() {
             // do some Main Thread work here.
        }
    });
}

用这样的方法,我们可以为网络任务,I/O任务,繁重的后台任务,及别的其它任务创建不同的线程池。

如何取消一个任务

为了取消一个任务,你需要得到任务的future,所以你需要调用submit方法来代替execute方法,submit方法将返回一个future对象,通过返回的future对象你就能执行取消任务的操作了。

/*
* Get the future of the task by submitting it to the pool
*/

Future future = DefaultExecutorSupplier.getInstance().forBackgroundTasks()
    .submit(new Runnable() {
    @Override
    public void run() {
    // do some background work here.
    }});

/*
* cancelling the task
*/
future.cancel(true);

如何设置任务的优先级

比如说在任务队列中有20个任务,线程池仅持有4个线程,因为线程池中的线程同时只能执行4个任务,所以我们按照任务的优先级来执行它们。

如果想让最后放入队列中的任务最先被执行,我们需要将它的优先级设置成IMMEDIATE

为了设置任务的优先级,我们需要先创建一个thread pool executor

创建线程优先级的枚举

/**
 * Priority levels
 */

public enum Priority {
    /**
    * NOTE: DO NOT CHANGE ORDERING OF THOSE CONSTANTS UNDER ANY CIRCUMSTANCES.
    * Doing so will make ordering incorrect.
    */

    /**
    * Lowest priority level. Used for prefetches of data.
    */

    LOW,

    /**
    * Medium priority level. Used for warming of data that might soon get visible.
    */

    MEDIUM,
    /**
    * Highest priority level. Used for data that are currently visible on screen.
    */
    HIGH,
    /**
    * Highest priority level. Used for data that are required instantly(mainly for emergency).
    */
    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;
    }

}

创建ThreadPoolExecutor的子类PriorityThreadPoolExecutor及实现了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(), 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中的ThreadPoolExecutor替换成PriorityThreadPoolExecutor。代码如下:

public class DefaultExecutorSupplier{

    private final PriorityThreadPoolExecutor mForBackgroundTasks;

    private DefaultExecutorSupplier() {

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

    }
}

下边是如何设置任务的优先级为HIGH的例子:

/*
* 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.
        }

    });
}

用这种方法,一个任务能够优先被执行。上边的实现也同样适用于java应用程序。

本篇文章到这儿就结束了,希望文章能够对你有所帮助,由于水平有限写得不好的地方还请谅解,如果你有任何建议或问题欢迎与我交流。

文章中的源码地址:https://github.com/amitshekhariitbhu/Fast-Android-Networking
本篇文章的内容主要参考自:https://medium.freecodecamp.com/threadpoolexecutor-in-android-8e9d22330ee3#.t6lb6a1t1

你可能感兴趣的:(android学习笔记)