安卓中使用ThreadPoolExcutor


title: 安卓中使用ThreadPoolExcutor
date: 2016-07-29 10:14:02
tags:

  • android
  • 翻译

这篇文章将涉及到线程池,线程池执行程序,和他们在Android中的使用。
我们将使用很多的利用,详细的(thoroughly)介绍这些主题。

Thread Pools (线程池)

一个线程池管理一池的工作线程(准确的数量依赖于它的实现方式)。
一个task队列等待池中的空闲线程执行队列中的task.Task被生产者加入队列中,工作线程作为消费者,只要池中有空闲线程在等待新的后台任务,就会从task队列中消费任务。

ThreadPoolExcutor

ThreadPoolExcutor 从线程池中的一个线程执行一个给定的task。

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

参数解释:

  1. corePoolSize: 线程池中保留线程的最小数目,最开始线程池中没有线程,但是随着task被加入队列,新线程被创建。如果有空闲的线程,但是线程的数目小于corePoolSize,就会创建新的线程。
  2. maximumPoolSize: 线程池中线程的最大值,如果线程数量超过corePoolSize,线程数量>=corePoolSize,那么只有队列满的时候才会创建新的工作线程。
  3. keepAliveTime: 当线程数量超过corepoolsize,非corepoolsize的空闲线程将等待一个新的task,如果在这个定义的时间参数内没有等到新的task,该线程将被终止。
  4. unit: keppAliveTime的时间单位
  5. workQueue: task队列,持有runnable task,必须是一个BlockingQueue.

为什么在Android和JAVA应用程序中使用Thread Pool Executor?

  1. 它是一个强大的任务执行框架,支持任务添加到队列,任务取消,任务优先级。
  2. 降低了线程创建的开销,它在线程池内管理一定数量的线程。

在Android中使用ThreadPoolExcutor

首先,创建一个PriorityThreadFactory:

import android.os.Process;

import java.util.concurrent.ThreadFactory;

/**
 * Created by Adam on 2016/7/29.
 */
public class PriorityThreadFactory implements ThreadFactory {
private final int mThreadPrority;

public PriorityThreadFactory(int mThreadPrority) {
    this.mThreadPrority = mThreadPrority;
}

@Override
public Thread newThread(final Runnable r) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                Process.setThreadPriority(mThreadPrority);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
            r.run();
            ;

        }
    };
    return new Thread(runnable);
}
}

创建一个MainThreadExecutor:

import android.os.Handler;
import android.os.Looper;
    
import java.util.concurrent.Executor;

/**
 * Created by Adam on 2016/7/29.
 */
public class MainThreadExecutor implements Executor {

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

@Override
public void execute(Runnable command) {

    handler.post(command);

}
}

创建一个DefaultExecutorSupplier:

import android.os.Process;

import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by Adam on 2016/7/29.
 */
public class DefaultExecutorSupplier {
/*
    *指定线程数量
 */
public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
/**
     * 后台任务的线程池
 */
private final ThreadPoolExecutor mForBackgroundTasks;
/**
     * 轻量后台任务的线程池
 */
private final ThreadPoolExecutor mForLightWeightBackgroundTasks;

/**
     * 主线程任务的线程池executor
 */
private final Executor mMainThreadExcutor;

private static DefaultExecutorSupplier mInstance;

/**
     * 返回DefaultExecutorSupplier的实例
 */
public static DefaultExecutorSupplier getInstance() {

    if (mInstance == null) {

        synchronized (DefaultExecutorSupplier.class) {
            mInstance = new DefaultExecutorSupplier();
        }
    }

    return mInstance;

}

private DefaultExecutorSupplier() {
    ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
    mForBackgroundTasks = new ThreadPoolExecutor(
            NUMBER_OF_CORES * 2,
            NUMBER_OF_CORES * 2,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(),
            backgroundPriorityThreadFactory

    );

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

    mMainThreadExcutor = 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 mMainThreadExcutor;
}


}

注意:不同线程池的数量依赖于你的需求

现在在你的代码中这样使用

    /*
    * 后台任务
    */
public void doSomeBackgroundWork() {
    DefaultExecutorSupplier.getInstance().forBackgroundTasks()
            .execute(new Runnable() {
                @Override
                public void run() {
                    // 在这里后台工作.
                }
            });
}

/*
    * 轻量后台任务
    */
public void doSomeLightWeightBackgroundWork() {
    DefaultExecutorSupplier.getInstance().forLightWeightBackgroundTasks()
            .execute(new Runnable() {
                @Override
                public void run() {
                    // 在这里做一些轻量后台工作.
                }
            });
}

/*
    * 主线程任务
    */
public void doSomeMainThreadWork() {
    DefaultExecutorSupplier.getInstance().forMainThreadTasks()
            .execute(new Runnable() {
                @Override
                public void run() {
                    // 做一些中线程工作.
                }
            });
}

这样,我们可以为网络任务,I/O任务,重型的后台任务和其他任务创建不同的线程池。

怎样取消一个task?

为了取消一个task,你必须得到task的future。所以,不要使用execute,使用submit,将返回一个future。现在future就可以用来取消task了。

 Future future= DefaultExecutorSupplier.getInstance().forBackgroundTasks()
            .submit(new Runnable() {
                @Override
                public void run() {

                }
            });

    future.cancel(true);

如何设置task的优先级?

假设队列里有20个任务,线程池持有4个线程,我们根据task的优先级处理他们,因为线程池此时同时可处理4个线程。

但是假设我们需要我们最后推进队列的任务最先执行,我们需要为该任务设置立即的优先当线程从队列里拿取新任务时。

为了设置任务的优先级,我们需要创建一个线程池executor。

为优先级创建一个枚举类:

/**
 * Created by Adam on 2016/7/29.
 */
public enum Priority {
/**
     * 注意:不要在任何情况下改变顺序,否则会使排序不准确
 */
/**
     * 最低优先级,预加载数据用
 */
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() {

}
public Priority getPriority(){
    return  priority;
}
}

创建一个PriorityThreadPoolExecutor,继承自ThreadPoolExecutor.我们必须创建PriorityFutureTask,将实现Comparable<PriorityFutureTask>接口。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by Adam on 2016/7/29.
 */
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, 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;
    }

    @Override
    public int compareTo(PriorityFutureTask another) {
        Priority p1 = priorityRunnable.getPriority();
        Priority p2 = another.priorityRunnable.getPriority();
        return p2.ordinal() - p1.ordinal();
    }
}
}

首先在DefaultExcutorSupplier,用PriorityThreadPoolExecutor代替ThreadPoolExecutor.

        ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
//        mForBackgroundTasks = new ThreadPoolExecutor(
//                NUMBER_OF_CORES * 2,
//                NUMBER_OF_CORES * 2,
//                60L,
//                TimeUnit.SECONDS,
//                new LinkedBlockingQueue<Runnable>(),
//                backgroundPriorityThreadFactory
//
//        );
    mForBackgroundTasks=new PriorityThreadPoolExecutor(
            NUMBER_OF_CORES * 2,
            NUMBER_OF_CORES * 2,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(),
            backgroundPriorityThreadFactory
    );

下面的例子演示了如何设置高优先级:

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

推荐阅读更多精彩内容