Android/Javaスレッド池のまとめ

6446 ワード

スレッドプールの利点:
  • はスレッドを再利用し、スレッドの作成と廃棄の性能オーバーヘッドを低減する。
  • は、スレッドを管理し、タイミング実行や間隔サイクル実行などの機能を提供する。
  • AndroidのスレッドはJavaのExectorに由来し、達成クラスはThreadPool Exectorであり、ThreadPool Exectorは構造方法の一連のパラメータを通じて、異なる配置のスレッド池を構成する。よく使われる構造方法は次の四つがあります。
    ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue workQueue) 
    
    ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue workQueue,
                            ThreadFactory threadFactory)
    
    ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue workQueue,
                            RejectedExecutionHandler handler)
    
    ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler)
    
    パラメータの説明
  • corePoolSizeコアスレッド数は、デフォルトではコアスレッドが常に生存しており、アイドル状態であってもkeep Alive Timeに制限されない。allowCoreThreadTimeOutをtrueに設定しない限り。
  • maximPoolSizeスレッド池に収容できる最大スレッド数。
  • keep Alive Time非コアスレッドのアイドルタイムアウト時間は、この時間を過ぎると回収されます。allowCoreThreadTimeOutをtrueに設定すると、コアスレッドも回収されます。
  • ユニットkeep Alive Timeの単位
  • work Queスレッド池のジョブキュー。よく使う列は4つあります。Synch ronousQue、Linked Blocking Deque、ArayBlocking Que、DelayQue。
  • threadFactoryスレッド工場は、新しいスレッドを作成する機能を提供します。スレッド工場を通じてスレッドのいくつかの属性をカスタマイズすることができます。
  • RejectedExecution Handlerは、スレッドの池にあるリソースが全部使用されていて、新しいスレッドを追加して拒否された場合、RejectedExecution HandlerのrejecteExecution方法を呼び出します。
  • スレッドプールのタスクキュー(重要)
    以下では、上記のような一般的な4つの列を紹介します。その前に、上記のパラメータに基づいて分析してみます。コアスレッド、非コアスレッド、タスクキューの3つのキャラクターがあります。彼らは現在の構成によって、それぞれの新たなタスクを処理することができます。(処理とは、スレッドを割り当ててタスクを実行するか、タスクをタスクキューに保存してスレッドを割り当てるかのことです。三つのキャラクターは、以下のように設計できます。コアスレッド+タスクキュー(キューサイズ設定可能)+無限のコアスレッド(正確には、corePoolSizeコアスレッド、maximPoolSize-coree PoolSize非コアスレッド)
    理解しやすくはないです。タスクが多い時、コアスレッドが足りなくなったら、タスクキューに保存します。列がいっぱいになったら、ノンコアスレッドを作成してタスクを実行します。このように設計されたのは2つの極端な状況が含まれています。つまり、列のサイズは0と列が無限大です。具体的な設計は以下の3つのようです。
  • 有限コアスレッド+無限のコアスレッドがあれば、新しいタスクを実行するスレッドを割り当てることができます。この時点でタスクキューのサイズは0です。
  • 有限コアスレッド+タスクキュー(キューが無限大)であれば、新しいタスクを実行するスレッドを割り当てることができ、スレッドレス割り当てをキューに保存することができます。
  • 有限コアスレッド+タスクキュー(キューサイズが限られていて、0ではない)+無限の非コアスレッド。
  • この3つの設計はworkQueパラメータの3つの列に対応しています。Synch rousQue、Linked Blocking Deque、ArayBlocking Que。
    Synch ronousQue
    新しいタスクを受信した場合は、スレッド処理に直接に任せます。スレッドがすべて稼働している場合は、このタスクを新しいスレッドで処理します。maximPoolSizeをInteger.MAXUVALEに指定すれば、無限スレッドです。(上記の第1の設計に対応)
    Linked Blocking Deque
    このキューにはサイズ制限がありません。新しいタスクを受信した場合、現在のスレッドがコアスレッド数より小さい場合は、新しいコアスレッド処理タスクが作成されます。現在のスレッド数がコアスレッド数に等しい場合は、キューに入ります。キューのサイズ制限がないため、最大スレッド数がコアスレッド数を超えないように設定が無効になります。(上記第2の設計に対応)
    ArayBlocking Que
    キューの長さを制限できます。タスクを受信した場合、corePoolSizeの値に達していない場合は、新規コアスレッドを作成してタスクを実行します。到達したら、入隊します。キューがいっぱいになったら、非コアスレッドを新規作成してタスクを実行します。maximPoolSizeに達したら、エラーが発生します。(上記3つの設計に対応)
    DelayQue
    列の要素はDelayedインターフェースを実現しなければなりません。これはあなたが送ったタスクが先にDelayedインターフェースを実現しなければならないということです。このキューがタスクを受信した時、先に入隊します。指定された遅延時間に達してこそ、任務を実行します。
    実際には、キューが無限大であり、コアスレッドが無数にあることは不可能であり、これらの列はスレッド総数を超えている場合があり、この場合はThreadPool Exectorの7番目のパラメータRejectExectionHandlerを配置するだけでよい。
    4種類のよくあるスレッド池
    以下に4つのシステムが提供する配置の良いスレッド池を紹介します。もちろん、上のジョブキューを理解すれば、自分で同じスレッドプールを配置するのは簡単です。この4つのスレッドプールはシステムのツール類Exectorsを使って作成されます。
    //      1              。
    Executors.newFixedThreadPool(1);
    Executors.newCachedThreadPool();
    Executors.newScheduledThreadPool(1);
    Executors.newSingleThreadExecutor();
    
    Fixed ThreadPool
    対応:限られたコアスレッド+タスク・キュー(列が無限大)->Linked Blocking Queの作成方法は、コアスレッド数を指定するためにパラメータを入力する必要があります。機能の特徴はよく分かります。以下は、アート・探索における説明です。
    スレッドの数が固定されているスレッド池です。スレッドがアイドル状態になったら、それらは回収されません。スレッドがオフされていない限り、すべてのスレッドがアクティブ状態になると、スレッドがアイドル状態になります。FixedThreadPoolはコアスレッドのみで、これらのコアスレッドは回収されないので、これはさらにスレッドがオフされることを意味します。外部要求に迅速に応答します。newFixedThreadPool方法のソースコードを通じて、FixedThreadPoolの中にコアスレッドだけがタイムアウトメカニズムがないことが分かります。また、タスクのキューもサイズ制限がありません。
    CachedThreadPool
    対応:限られたコアスレッド+無限のノンコアスレッド-->SyncronousQueコアスレッド数は0であるので、その作成方法にはパラメータは必要ありません。以下はアート探索中の説明です。
    スレッド数が不定のスレッド池で、コアスレッドのみであり、最大スレッド数はInteger.MAXUVALEである。Integer.MAXUVALEは大きな数であるため、実際には最大スレッド数に相当する任意の大きさである。スレッド池中のスレッドがアクティブな状態になると、新しいスレッドを作成して新しいタスクを処理する。アイドルスレッドを利用する。を選択して、新しいタスクを処理します。スレッドの中のアイドルスレッドはタイムアウト機構があります。タイムアウトは60秒で、60秒以上放置されているスレッドは回収されます。FixedThreadPoolとは異なり、CachedPoolのタスクキューは空セットに相当します。これは、どのタスクもすぐに実行されます。このようなスレッドプールは、大量の実行に適しています。スレッドのプール全体がアイドル状態にあると、すべてのスレッドがタイムアウトして停止されます。この時、CachedThreadPoolには実際にはスレッドがありません。システムリソースはほとんど占められません。
    SchduledThreadPool
    対応:DelayQueその作成方法は、コアスレッド数を指定するパラメータが必要です。以下のように説明します。
    コアスレッド数は固定であり、コアスレッド数ではなく制限されていません。このスレッドプールは主にタイミングタスクと一定周期の繰り返しタスクを実行するために使用されます。
    SingleThreadExector
    対応:限られたコアスレッド+タスクキュー(列が無限大)->Linked Blocking QueとFixedThreadPoolの違いは、SingleThreadExectorはコアスレッドしかないので、その作成方法はパラメータなしである。
    この種のスレッドプールの内部にはコアスレッドが一つしかありません。すべてのタスクは同じスレッドの中で順次実行されることを保証します。つまり、すべての外界のタスクを一つのスレッドに統合することで、これらのタスクの間でスレッド同期の問題を処理する必要がなくなります。
    最後にスレッドを使用するいくつかの例があります。
    Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
        }
    };
    
    //        
    ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(2, 10, 5, TimeUnit.SECONDS, new SynchronousQueue());
    //  myRunnable  
    myExecutor.execute(myRunnable);
    
    //        
    ExecutorService fixedExecutor = Executors.newFixedThreadPool(1);
    //  myRunnable  
    fixedExecutor.execute(myRunnable);
    
    //        
    ScheduledExecutorService sExecutor = Executors.newScheduledThreadPool(1);
    //2000ms   myRunnable
    sExecutor.schedule(myRunnable, 2000, TimeUnit.MILLISECONDS);
    //10ms ,  1000ms    myRunnable
    sExecutor.scheduleAtFixedRate(myRunnable, 10, 1000, TimeUnit.MILLISECONDS);
    
    文章の参考
    「Android開発芸術探査」Javaマルチスレッド-スレッド池ThreadPool Exector構造方法とルールスレッド池、これで十分かもしれません。