Androidのスレッドプール-[Android_YangKe]

9381 ワード

スレッドプールといえば、まずスレッドプールのメリットを話さなければなりません.読者が知っていると信じています.スレッドプールのメリットは以下の3つにまとめることができます.
  • スレッドプール内のスレッドを再利用し、スレッドの作成と破棄によるパフォーマンスオーバーヘッドを回避します.
  • は、スレッドプールの最大同時数を効果的に制御し、大量のスレッド間でシステムリソースを奪い合うことによるブロック現象を回避することができる.
  • は、スレッドを簡単に管理し、タイミング実行や指定間隔ループ実行などの機能を提供することができる.

  • Androidのスレッドプールの概念はJavaのExecutorに由来し、Executorはインタフェースであり、真のスレッドプールの実現はThreadPoolExecutorである.ThreadPoolExecutorは一連のパラメータを提供してスレッドプールを配置し、異なるパラメータによって異なるスレッドプールを作成することができ、スレッドプールの機能特性から言えばAndroidのスレッドプールは主に4種類に分けられ、この4種類のスレッドプールはExecutorが提供した工場方法で得ることができ、具体的にはThreadPoolExecutorで詳しく紹介する.Androidのスレッドプールは、ThreadPoolExecutorを直接または間接的に構成することによって実現されるため、それらを紹介する前にThreadPoolExecutorを紹介する必要があります.
    ThreadPoolExecutor ThreadPoolExecutorはスレッドプールの真の実装であり、その構造方法は一連のパラメータを提供してスレッドプールを構成し、以下にThreadPoolExecutorの構造方法における各パラメータの意味を紹介し、これらのパラメータはスレッドプールの機能特性に直接影響し、以下はThreadPoolExecutorの比較的一般的な構造方法である.
    public ThreadPoolExecutor (int corePoolSize, 
                               long maximumPoolSize,
                               long keepAliveTime,
                               TimeUnit unit,
                               BlockingQueue workQueue,
                               ThreadFactory threadFactory)
    

    CorePoolSizeスレッドプールのコアスレッド数です.デフォルトでは、コアスレッドはアイドル状態であってもオンラインスレッドプールで生存します.ThreadPoolExecutorallowCoreThreadTimeOutプロパティがtrueに設定されている場合、アイドルコアスレッドは、新しいタスクが来るのを待つときにタイムアウトポリシーがあります.この間隔はkeepAliveTimeで指定され、待ち時間がkeepAliveTimeで指定された時間を超えると、コアスレッド数は終了します.
    maximumPoolSizeスレッドプールに収容できる最大スレッド数は、アクティブなスレッドがこの数値に達すると、後続の新しいタスクがブロックされます.
    keepAliveTime非コアスレッドアイドル時のタイムアウト時間が長く、それを超えると非コアスレッドが回収され、ThreadPoolExecutorallowCoreThreadTimeOut属性がtrueに設定されている場合、keepAliveTImeもコアスレッドに作用する.
    unitは、keepAliveTimeパラメータの時間単位を指定するために使用され、これは列挙であり、TimeUnit.MILLISECONDS(ミリ秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)などが一般的である.
    WorkQueueスレッドプール内のタスクキューでは、スレッドプールのexecuteメソッドでコミットされたRunnableオブジェクトがこのパラメータに格納されます.
    threadFactoryスレッドファクトリは、スレッドプールに新しいスレッドを作成する機能を提供します.ThreadFactoryはインタフェースであり、Thread newThread(Runnable r)という方法しかありません.
    これらの主要パラメータに加えて、ThreadPoolExecutorには一般的でないパラメータRejectedExecutionHandler handlerがある.スレッドプールが新しいタスクを実行できない場合、これは、タスクキューがいっぱいになっているか、タスクが正常に実行できないためかもしれません.この場合、ThreadPoolExecutorはhandlerのrejectedExecutionメソッドを呼び出して呼び出し、デフォルトではrejectedExecutionメソッドがRejectedExecutionExceptionを直接投げ出します.ThreadPoolExecutorは、RejectedExecutionHandlerにいくつかのオプション値を提供します.CallerRunsPolicy、AbortPolicy、DiscardPolicy DiscardOldesPolicyはデフォルト値であり、AbortPolicyは直接RejectedExecutionExceptionを放出します.handlerというパラメータは一般的ではないので、ここでは詳しく説明しません.ThreadPoolExecutorタスクを実行するときは、次のルールに従います.
  • スレッドプールのスレッド数がコアスレッドプールの数に達していない場合、タスクを実行するためにコアスレッドが直接起動します.
  • スレッドプール内のスレッドの数がコアスレッドの数に達しているか、またはそれを超えている場合、タスクはタスクキューに挿入されてキュー実行されます.
  • ステップ2でタスクをタスクキューに挿入できない場合は、タスクキューがいっぱいになっているため、スレッド数がスレッドプールで指定された最大値に達していない場合、すぐに非コアスレッドが起動してタスクを実行します.
  • ステップ3でスレッド数がスレッドプールによって規定された最大値に達した場合、このタスクの実行は拒否され、ThreadPoolExecutorは、RejectedExecutionHandlerrejectedExceptionメソッドを呼び出して呼び出し、呼び出し元に通知する.
  • ThreadPoolExecutorのパラメータ構成はAsyncTaskで明らかになっています.以下はAsyncTaskのスレッドプールの構成です.
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;
    
    private static final ThreadFactory sThreadFactory = new ThreadFactory () {
        private static final int AtomicInteger mCount = new AtomicInteger (1);
    
        public Thread newThread (Runnable r) {
            return new Thread (r, "AsyncTask #" + mCount.getAndIncrement ());
        }
    
        private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue (128);
    
    /**
        * An {@link Executor} that can be used to execute tasks in paralleb.
         */
        public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor (CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    } ;
    

    上記のコードから分かるように、AsyncTaskTHREAD_POOL_EXECUTORというスレッドプールを配置し、配置後のスレッドプールの規格は以下の通りである.
  • コアスレッド数はCPUコア数+1に等しい.
  • スレッドプールの最大スレッド数CPUコア数の2倍+1;
  • コアスレッドにはタイムアウトメカニズムがなく、非コアスレッドのアイドル時のタイムアウト時間は1秒である.
  • タスクキューの容量は128です.

  • スレッドプールの分類
    上記では、ThreadPoolExecutorの構成について詳しく説明しましたが、このセクションでは、Androidで最も一般的な4つの異なる機能特性を有するスレッドプールについて説明します.これらの4つのスレッドプールは、それぞれThreadPoolExecutorであるFixedThreadPool、CachedThreadPool、ScheduleThreadPool SingleThreadPoolを直接または間接的に構成することによって独自の機能特性を実現します.
    FixedThreadPool ExecutorsnewFixedThreadPoolメソッドによって作成されます.スレッド数が固定されたスレッドプールであり、スレッドプールが閉じられない限り、スレッドプールがアイドル状態にある場合、スレッドプールは回収されません.すべてのスレッドがアクティブな場合、新しいタスクは新しいスレッドが空になるまで待機します.FixedThreadPoolはコアスレッドのみであり、これらのコアスレッドは回収されないため、外部の要求により迅速に応答できることを意味する.newFixedThreadPool方法の実装は、FixedThreadPoolの中にコアスレッドのみが存在し、これらのコアスレッドにはタイムアウト制限がなく、またタスクキューにもサイズ制限がないことを発見することができる.
    public static ExecutorService newFixedThreadPool (int nThreads) {
        return new ThreadPoolExecutor (nThreads, nThreads,
                                       0L, TimeUnit.MILLISENONDS, 
                                       new LinkedBlockingQueue());
    }
    

    CachedThreadPool
    ExecutorのnewCachedThreadPoolメソッドで作成します.非コアスレッドのみであり、最大スレッド数はInteger.MAX_VALUEです.Integer.MAX_VALUEは大きな数であるため、実際には最大スレッド数に相当して任意に大きくすることができる.
    スレッドプール内のスレッドがアクティブな場合、スレッドプールは新しいスレッドを作成して新しいタスクを処理します.そうしないと、空きスレッドを使用して新しいタスクを処理します.スレッドプール内の空きスレッドにはタイムアウトメカニズムがあり、このタイムアウト時間は60秒で、60秒を超えるとアイドルスレッドが回収されます.FixedThreadPoolとは異なり、CachedThreadPoolのタスクキューは実際には空のセットに相当し、このようなシナリオではSynchronousQueueはタスクを挿入できないため、任意のタスクが直ちに実行される.SynchronousQueueは非常に特殊なキューであり、多くの場合、要素を格納できないキューを簡単にすることができます.実際には使用されていないため、ここでは深く検討しません.
    スレッドプール全体がアイドル状態にある場合、スレッドプール内のスレッドはタイムアウトして停止されます.この場合、CachedThreadPoolには実際にはスレッドはなく、ほとんどシステムリソースを占有しません.newCacheThreadPoolの方法の実装を以下に示す.
    public static ExecutorService newCachedThreadPool () {
        return new ThreadPoolExecutor (0, 
                                       Integer.MAX_VALUE, 60L, 
                                       TimeUnit.SECONDS, 
                                       new SynchronousQueue());
    }
    

    ScheduledThreadPool
    ExecutorsのnewScheduledThreadPoolメソッドによって作成されます.コアスレッドの数は固定されており、コアスレッドの数ではなく制限されず、非コアスレッドがアイドル状態にある場合にすぐに回収されます.ScheduledThreadPoolのようなスレッドプールは、主にタイミングタスクと周期的な繰返しタスクを実行するために使用され、newScheduledThreadPoolの方法の実装は以下に示す.
    public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize) {
        return new ScheduledThreadPoolExecutor (corePoolSize);
    }
    
    public ScheduledThreadPooExecutor (int corePoolSize) {
        super (corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
    }
    

    SingleThreadExecutor
    ExecutorsのnewSingleThreadPoolExecutorメソッドによって作成されます.このようなスレッドプールの内部には、すべてのタスクが同じスレッドで順次実行されることを保証するコアスレッドが1つしかありません.SingleThreadPoolExecutorは、すべての外部タスクを1つのスレッドに統一することを意味し、これらのタスク間でスレッド同期の問題を処理する必要がない.newSingleThreadExecutorの方法の実装を以下に示す.
    public static ExecutorService newSingleThreadExecutor () {
        return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor (
                                                              1, 
                                                              1,
                                                              0L, 
                                                              TimeUnit.MILLISECONDS, 
                                                              new LinkedBlockingQueue());
    }
    

    Androidでよく見られる4種類のスレッドプールについて詳しく説明したが、上記システムが提供する4種類のスレッドプールのほか、実際のニーズに応じてスレッドプールを柔軟に構成することもできる.次のコードは,システムプリフォームの4つのスレッドプールの使用方法を示す.
    Runnable command = new Runnable (){
        @Override
        public void run (){
            SystemClock.sleep(2000);
        }
    };
    
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
    fixedThreadPool.execute(command);
    
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    cachedThreadPool.execute(command);
    
    ScheduledExecutorService scheduleThreadPool = Executors.newScheduledThreadPool(4);
    //2000ms     command
    scheduleThreadPool.schedule(command, 2000, TimeUnit.MILLISECONDS);
    //   10ms  ,   1000ms      command
    scheduleThreadPool.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MILLISECONDS);
    
    ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
    singleThreadExecutor.execute(command);
    

    注:Androidからアートを開発しました~
    助けがあれば、ダブルクリック、コメント、転送、あなたの小さな手を動かしてもっと多くの人に知ってもらうのが好きです!Androidに注目YangKe