Androidステップアップ-スレッドプール

4821 ワード

前回の記事(なぜ学ぶのか)でAsyncTaskの原理がスレッドプールに言及されたので、Androidを学ぶスレッドプールを学びましょう.では、スレッドプールにどのような利点があるのか、あるいはなぜスレッドプールを学ぶのかを見てみましょう.
  • は、スレッドプール内のスレッドを再利用し、スレッドの新規作成と破棄のメモリオーバーヘッドを回避します.
  • は、スレッドプールの最大同時数を有効にし、大量のスレッド間でシステムリソースを奪い合い、ブロック現象を回避することができる.
  • は、スレッドを簡単に管理し、タイミング実行や指定間隔ループ実行などの機能を提供することができる.

  • ベーススレッドプール
    よく使われるスレッドプールはたくさんありますが、まずベーススレッドプールThreadPoolExcutorを見てみましょう.他の一般的なスレッドプールはThreadPoolExcutorに基づいて実現されています.では、まずその構造方法から始めましょう.
        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue workQueue,
                                  ThreadFactory threadFactory) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 threadFactory, defaultHandler);
        }
    

    パラメータ:corePoolSizeスレッドプールのコアスレッド数.デフォルトでは、スレッドがアイドル状態であっても、コアスレッドは常に存在します.パラメータ:maximumPoolSizeスレッドプールに収容できる最大スレッド数は、コアスレッドが足りない場合、非コアスレッドを開いてタスクを処理し、maximumPoolSize=corePoolSize+非コアスレッド数パラメータ:keepAliveTime非コアスレッドがタスクを処理してアイドル状態にある場合、一定時間の範囲で再利用されなければ破棄されます.keepAliveTimeは前述した一定の時間範囲である.パラメータ:unitには時間範囲があり、もちろん時間の単位を決定します.このパラメータは時間範囲を記述するパラメータです.これは列挙パラメータで、よく使われています:TimeUnit.DAYS TimeUnit.HOURS TimeUnit.MINUTESパラメータ:workQueueスレッドプールのタスクキュー、スレッドプールのexcuteメソッドでコミットされたタスクがこのキューに入ります.パラメータ:threadFactoryスレッドプールに新しいスレッドを作成する方法-->newThread(Runnale r)
    ThreadPoolExcutorがタスクを実行する際に概ね遵守するルール:
  • スレッドプール内のスレッド数がコアスレッド数に達していない場合、タスク
  • を実行するためにコアスレッドを新たに開きます.
  • コアスレッドの数以上に達した場合、タスクキューに挿入され、
  • の実行を待つ.
  • タスクキューがいっぱいになった場合、タスクを実行するために非コアスレッドが新たに開きます.
  • スレッド数が最大値に達すると、タスクの実行が拒否されます.

  • OK、そんなにたくさん説明したのに実践しないで、次の例を見てみましょう.
    mExecutor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, new ArrayBlockingQueue(5));//    mExecutor 
    
    fab.setOnClickListener(new View.OnClickListener() {//        
        @Override
        public void onClick(View view) {
            num++;
            mExecutor.execute(new MyRunnable(String.valueOf(num)));
            Log.d(TAG, "           : "+String.valueOf(mExecutor.getPoolSize()));
            Log.d(TAG, "       : "+String.valueOf(mExecutor.getCompletedTaskCount()));
        }
    });
            
    
    

    共通スレッドプール
    FixedThreadPoolコアスレッドのみのスレッドプールであり、スレッドは回収されず、タスクに迅速に応答でき、タスクキューにもサイズ制限がないことを意味します.FixedThreadPoolのインスタンス化方法:
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue());
        }
    

    例:
    ExecutorService e = Executors.newFixedThreadPool(5);
    e.execute(new MyRunnable(String.valueOf(num)));
    

    CachedThreadPoolこれはスレッド数が不確定なスレッドプールである、以下の実例化方法から分かるように、コアスレッドは0、非コアスレッドはIntegerである.MAX_VALUE、これは大きな数です.タイムアウトポリシーは60秒です.また、SynchronousQueueは、要素を格納できないキューです.つまり、新しいタスクがあるたびに、すぐにスレッドが開きます.すべてのタスクが完了すると、スレッドプールに0スレッドが存在する場合もあります.したがって、システムリソースはほとんど占有されません.CachedThreadPoolのインスタンス化方法:
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }
    

    例:
    ExecutorService e2 = Executors.newCachedThreadPool();
    e2.execute(new MyRunnable(String.valueOf(num)));
    

    ScheduledThreadPoolは,コアスレッドが固定され,非コアスレッドが大きいスレッドプールであることを以下のインスタンス化法から示す.DEFAULT_KEEPALIVE_MILLIS=10 L、つまりタイムアウトポリシーは10ミリ秒です.インスタンス化方法:
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }
    

    例:
    ExecutorService e3 = Executors.newScheduledThreadPool(5);
    e3.execute(new MyRunnable(String.valueOf(num)));
    

    SingleThreadPoolは、次のインスタンス化方法から、このスレッドプールには、コアスレッドが1つしかないことがわかります.すべてのタスクが同じスレッドで実行されることを保証し、スレッド同期の問題を処理する必要がないという意味です.インスタンス化方法:
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }
    

    例:
    ExecutorService e4 = Executors.newSingleThreadExecutor();
    e4.execute(new MyRunnable(String.valueOf(num)));
    

    まとめ
    一連の学習に入ったことがあり、スレッドプールについても初歩的な理解があったが、理解は理解に帰し、実際の開発に応用する上で優位性があるのは別のことだ.もっと実際と結びつけなければなりません.
    参考文献:『Android開発芸術探索』