在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<Runnable> workQueue
);

这些参数都是什么意思?

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

        // setting the thread pool executor for mForLightWeightBackgroundTasks;
        mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
                 NUMBER_OF_CORES * 2,
                 NUMBER_OF_CORES * 2,
                 60L,
                 TimeUnit.SECONDS,
                 new LinkedBlockingQueue<Runnable>(),
                 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;
    }
}

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

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

/*
* 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<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中的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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容