在android中使用ThreadPoolExector

分類:技術 時間:2016-10-24

本篇文章主要介紹線程池,線程池executors及它們在android中的使用。我將使用一些例子代碼來進行講解。

Thread Pools

線程池管理著一些工作線程(實際的線程數取決于具體的實現)。

任務隊列(task queue)持有一些任務,這些任務等待著被線程池中的空閑線程執行。任務被生產者加入到任務隊列中。工作線程(worker threads)扮演著消費者的角色。當一個空閑線程準備完畢將會從任務隊列中取出一個任務在后臺進行執行。

ThreadPoolExecutor

ThreadPoolExecutor使用線程池中的線程執行給定的任務

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(

int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueuelt;Runnablegt; 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 LinkedBlockingQueuelt;Runnablegt;(),
                backgroundPriorityThreadFactory
        );

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

    @Override
    public Futurelt;?gt; submit(Runnable task) {
        PriorityFutureTask futureTask = new PriorityFutureTask((PriorityRunnable) task);
        execute(futureTask);
        return futureTask;
    }

    private static final class PriorityFutureTask extends FutureTasklt;PriorityRunnablegt;
            implements Comparablelt;PriorityFutureTaskgt; {
        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


Tags: 安卓開發

文章來源:http://www.jianshu.com/p/af657bd351ed


ads
ads

相關文章
ads

相關文章

ad