如何在安卓中使用线程池(ThreadPoolExecutor)

如何在安卓中使用线程池(ThreadPoolExecutor)

标签(空格分隔): 翻译计划


原文链接地址:Using ThreadPoolExecutor in Android

这篇文章将会覆盖线程池、线程池执行者、和怎么把他们使用到安卓里面。我们将会介绍这些主题,并且会附有许多示例代码。

线程池(Thread Pools)

一个线程池管理者一个工作线程池(线程池确定的个数取决于我们如何实现的)

一个任务队列保持着等待的任务,这些任务将会被线程池中的等待线程执行。生产者把任务添加到队列中,而工作线程作为消费者,只要有空闲的线程准备好执行任务,就从任务队列中取出任务并且消耗掉它。

线程执行者(ThreadPoolExecutor)

ThreadPoolExecutor则使用线程池中的一个线程来执行给定的任务
创建一个线程执行者:

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

这些参数的含义

  • 1、corePoolSize
    • 线程池中的最小线程个数,最初的线程池个数初始化是0个,但是当我们把任务添加到队列中的时候,一个新的线程将会被创建,如果有空线程,但是线程数低于corePoolSize,那么新的线程将会被继续创建
  • 2、maximumPoolSize
    • 线程池中允许创建的最大线程个数,如果这个数字超过了corePolSize,并且currentPoolSize>=corePoolSize,那么只有当队列满的时候才会去创建新的工作线程。
  • 3、keepAliveTime
    • 线程存活时间,当线程数大于核心线程(工作线程),那么非核心线程(多于的空闲线程)将等待新的任务,如果这些线程在该参数定义的时间内没有得到任务去执行,将会被销毁。
  • 4、unit
    • 线程存活时间keepAliveTime的时间单位
  • 5、workQueue
    • 工作队列,将会持有持续运行任务,这里将会展现BlockingQueue

安卓和Java中为什么会用到线程池

  • 1、这是一个强大的任务执行框架,支持队列中的任务添加,任务取消和任务优先级排序
  • 2、它可以减少线程创建的开销,因为他会在线程池中管理所需要的线程

在安卓中使用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;
    }
}

现在在你的代码逻辑中使用吧

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

通过这种方式,我们可以创建不同的线程池来服务于网络任务/IO任务/(后台)耗时任务、还有其他任务。

如何取消任务

当我们取消一个任务的时候,我们需要得到一个Future,而不是直接执行,因此我们需要使用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个任务。

假设我们需要在队列中首先执行最后一个任务,我们可以为这个线程设置IMMEDIATE优先级,以便于我们在队列中获取新任务的时候,将会执行此任务(因为这个标志的任务具有最高优先级)

要设置任务的优先级,我们需要创建一个线程池执行器

创建枚举优先级

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

创建一个优先级线程

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(优先级线程执行者)继承于ThreadPoolExecutor,我们还需要创建一个PriorityFutureTask,实现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
        );

    }
}

给一个如何给一个任务设置优先级的例子

/*
* 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 Applications

这里给一个我自己封装的安卓网络工作的依赖库Android Networking Library

如果想知道更详细的实现,可以查看DefaultExecutorSupplier.java这个类在Android Networking here.

我希望这些知识对于你有些帮助

感谢您阅读本文。
如果您发现它有用,请务必点击下面的❤推荐这篇文章。

如果想知道更多的关于程序设计方面的知识, follow me and Mindorks ,以便于我们更新新的技术文章的时候会通知到你。

Check out all the Mindorks best articles here.

Also, Let’s become friends on Twitter, Linkedin, Github and Facebook.

当然了最后的这些推荐都是需要翻墙的,这个就需要大家墙一下了哈.这里推荐给大家一个翻墙的网址,需要收费的,但是非常便宜的(最低的套餐一个月15G/1.5元 一年才18(现在搞活动)),可以看一下

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

推荐阅读更多精彩内容

  • 原文链接:http://blog.csdn.net/u010687392/article/details/4985...
    xpengb阅读 1,319评论 0 1
  • 前段时间遇到这样一个问题,有人问微信朋友圈的上传图片的功能怎么做才能让用户的等待时间较短,比如说一下上传9张图片,...
    加油码农阅读 1,197评论 0 2
  • 本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。 Android沿用了Java的线程模式,其中线程也分主线...
    阿敏其人阅读 2,787评论 6 50
  • 作者:肥肥鱼链接:https://www.zhihu.com/question/30804052/answer/4...
    TTTqiu阅读 961评论 0 4
  • 第一章 开学记 "叮铃铃……"讨厌的闹钟又响起了,我慢慢的起床,刚准备穿鞋,可……被妹妹吓了一大跳...
    小栀虞阅读 204评论 0 1