Executorフレームワークとスレッドプールの簡単な紹介

エグゼキュータフレームワーク

 

エグゼキュータ

これは、void execute(Runnable command);の実装のみを必要とするインターフェースであり、要件は、さまざまな状況(新しく開かれたスレッド、スレッドプールなど)で同期的に(executeメソッドですぐに実行する)タスクを完了することです。または非同期的に。



Executorインターフェースを実装するための独自のクラスを定義します。

パブリッククラスT_MyExecutorはExecutorを実装します{

    @オーバーライド

    public void execute(Runnable command){

         command.run();

    }

    public static void main(String [] args){

        new T_MyExecutor()。execute(()-> {

 

            System.out.println( "hello executor");

        });

}

}

ExecutorService

Executorから継承されたインターフェースは、Executorを拡張し、いくつかのライフサイクル管理メソッドを追加します。

ExecutorServiceのライフサイクルには、実行中、シャットダウン、および中止の3つの状態があります。

ExecutorService.shutdown()が呼び出されると、シャットダウン状態になり、isShutdown()メソッドはtrueを返します。現在、新しいタスクを追加することはできません。

追加されたすべてのタスクが閉じられると、Executorは終了状態になり、isTerminated()はtrueを返します。これには、shutdownまたはshutdownNowが以前に呼び出されている必要があります。awaitTerminationブロッキングを使用して、すべてのタスクが閉じられるのを待つことができます。

さらに、より多くの送信と呼び出しが呼び出されます。

submitとexecutorの違いは、その入力パラメーターがRunnableまたはCallableであり、戻り値Future <?>があることです。

呼び出しシステムの着信パラメーター(invokeAll、invokeAny)はすべて、Collection <?extends Callable <T >>タスクを持ち、TまたはTのコレクションを返します。

将来のFutureTask

Future <V>は、非同期で実行される操作を指定するインターフェイスです。操作の結果は、get()メソッドを介して取得できます。非同期操作が完了していない場合、get()は現在のスレッドをブロックします。待ち時間を指定できます。cancelメソッドは操作をキャンセルします。

FutureTask <V>は、RunnableFuture <V>を実装するクラスです。このインターフェイスはRunnableを継承し、Future <V>
はCallable <V>を保持します。コンストラクターにはCallable <V>が必要ですが、Runnable
(変換this.callable)を受け入れることもできます。= Executors.callable(runnable、result);)
非同期の原則:

  • 揮発性のint状態を保持します。これは、新しく構築されたか、完了したか、キャンセルされたかに関係なく、サーフェス上の現在の状態です。
  • 内部クラスWaitNodeは、スレッドを格納するリンクリストです。現在のノードは現在のスレッドを指し、nextは次に使用可能なスレッドを指します。CAS操作で実行中のスレッドを変更します。
  • LockSupport.parkが操作の完了前に取得をブロックすることにより、LockSupport.unparkはブロックを解除します。


CompletableFuture

非同期プログラム実行の別の方法を提供します。コールバック。future.get()のような非同期結果を取得するためにスレッドをブロックする必要はありません。またはisDoneを使用して、後続のプログラムを実行するために非同期スレッドが完了したかどうかを検出します。

・複数の非同期プロセスを管理し、完了した非同期プロセスを選択して、必要に応じて結果を返す機能。


複数のCompletableFutureタスクの管理

実際のアプリケーションでは、同時に複数の非同期タスクが存在する場合があります。次の操作を実行するためにそれらを一緒に完了する必要がある場合もあれば、結果があった場合にのみ戻る必要がある場合もあります。

次の場合:

 

あなたがサービスを提供できるとしましょう

このサービスは、主要なeコマースWebサイトで同じタイプの製品の価格を照会し、それらを一緒に表示します

 

パブリッククラスT_CompletableFuture {

 

    public static void main(String [] args){

        長いスタート、終わり;

 

        start = System.currentTimeMillis();

 

        CompletableFuture <Double> futureTM = CompletableFuture.supplyAsync(()->

                priceOfJD());

 

        CompletableFuture <Double> futureTB = CompletableFuture.supplyAsync(()->

                priceOfTB());

 

        CompletableFuture <Double> futureJD = CompletableFuture.supplyAsync(()->

                priceOfTM());

 

        CompletableFuture.allOf(futureTM、futureTB、futureJD).join();

 

        end = System.currentTimeMillis();

 

        System.out.println( "use completable future!" +(end --start));

 

        {を試してください

            System.in.read();

        } catch(IOException e){

            e.printStackTrace();

        }

 

    }

 

    private static double priceOfTM(){

        ディレイ();

        1.00を返します。

    }

 

    プライベート静的ダブルpriceOfTB(){

        ディレイ();

        2.00を返します。

    }

 

    プライベート静的ダブルpriceOfJD(){

        ディレイ();

        3.00を返します。

    }

 

 

    private static void delay(){

        int time = new Random()。nextInt(500);

        {を試してください

            TimeUnit.MILLISECONDS.sleep(time);

        } catch(InterruptedException e){

            e.printStackTrace();

        }

        System.out.printf( "%sスリープ後!\ n"、時間);

    }

}

 

 

 

ThreadPoolExecutor

ThreadPoolExecutorは、ExecutorServiceを実装するAbstractExecutorServiceを継承します。
最初に、ExecutorServiceのメソッド、
コンストラクター、およびパラメーターを実装します


 

・CorePoolSize:コアスレッドの数

・MaximumPoolSize:スレッドの最大数

・KeepAliveTime:スレッドのアイドル時間

・TimeUnitタイムスケール

・待機中のスレッドを格納するために使用されるWorkQueueブロッキングキュー

・ThreadFactoryスレッドファクトリ。内部ワーカーにスレッドを提供します。

・RejectedExecutionHandler:タスク拒否プロセッサ
は、タスク拒否戦略を処理する4つの方法を提供します

  1. 直接破棄(DiscardPolicy)
  2. キュー内の最も古いタスクを破棄します(DiscardOldestPolicy)。
  3. 例外をスローします(AbortPolicy)
  4. 実行のために呼び出しスレッドにタスクを割り当てます(CallerRunsPolicy)。

例えば:

パブリッククラスT_HelloThreadPool {

 

    静的クラスTaskはRunnableを実装します{

 

        private int i;

 

        public Task(int i){

            this.i = i;

        }

 

        @オーバーライド

        public void run(){

            System.out.println(Thread.currentThread()。getName()+ "タスク" + i);

            {を試してください

                System.in.read();

            } catch(IOException e){

                e.printStackTrace();

            }

        }

 

        @オーバーライド

        public String toString(){

            return "Task {" + "i =" + i + "}";

        }

    }

 

    public static void main(String [] args){

        ThreadPoolExecutor tpe = new ThreadPoolExecutor(2、4、60、TimeUnit.SECONDS、

                新しいArrayBlockingQueue <>(4)、

                Executors.defaultThreadFactory()、

                新しいThreadPoolExecutor.CallerRunsPolicy());

 

        for(int i = 0; i <8; i ++){

            tpe.execute(new Task(i));

        }

 

        System.out.println(tpe.getQueue());

 

        tpe.execute(new Task(100));

 

        System.out.println(tpe.getQueue());

 

        tpe.shutdown();

 

    }

}



結果:

 

 

コアスレッドは2、最大スレッドは4、タスクキューの容量は4、最大で8つのタスクを配置できます。

9番目のタスクが追加されると、CallerRunsPolicy拒否ポリシーが選択されているため、9番目のタスクがメインスレッドによって呼び出されます。

 

タスクエグゼキュータとしてワーカークラス、スレッドプールとしてHashSet <Worker>ワーカー、待機キューとしてworkQueueがあります。

状態は、最終的なAtomicInteger ctlによって保存されます
。5つの状態:

  • RUNNINGは、新しいタスクを受け入れ、キュー内のタスクを処理します
  • SHUTDOWNは新しいタスクを受け入れませんが、キュー内のタスクを処理します
  • STOPは新しいタスクを受け入れず、キュー内のタスクを処理せず、処理中のタスクを中断します
  • すべてのタスクが閉じられている(終了している)、workerCountが0の場合、呼び出しは終了します 
  • TERMINATED終了が呼び出されました



状態遷移:

  • RUNNING-> SHUTDOWNは、おそらくfinalize()で暗黙的にshutdown()を呼び出します
  • (RUNNINGまたはSHUTDOWN)-> shutdownNow()が呼び出されたときに停止
  • シャットダウン->キューとプールが空の場合の整理
  • プールが空のときに停止->整理
  • TIDYING-> terminateed()呼び出しが終了するとTERMINATED

戦略の実行:次の
3つのステップに進みます。

  • corePoolSize未満のスレッドが実行されている場合は、このタスクを処理するための新しいスレッドを作成してみてください。addWorkerメソッドは、実行ステータスとworkerCountをチェックします。
  • スレッドをキューから削除できる場合は、ステータスを確認して、新しいスレッドを追加するか、タスクをキャンセルするかを決定します。
  • キューからスレッドを取得できない場合は、新しいスレッドを追加します。失敗した場合は、このタスクをキャンセルしてください。



スレッドプールの作業プロセスは次のとおりです(個別の要約に転送)。

  1. スレッドプールが最初に作成されたとき、その中にスレッドはありませんでした。タスクキューはパラメータとして渡されます。ただし、キューにタスクがある場合でも、スレッドプールはそれらをすぐには実行しません。
  2. execute()メソッドを呼び出してタスクを追加すると、スレッドプールは次の判断を下します。
    1. 実行中のスレッドの数がcorePoolSize未満の場合は、すぐにこのタスクを実行するスレッドを作成します。
    2. 実行中のスレッドの数がcorePoolSize以上の場合は、タスクをキューに入れます。
    3. この時点でキューがいっぱいで、実行中のスレッドの数がmaximumPoolSize未満の場合でも、このタスクを実行するにはスレッドを作成する必要があります。
    4. キューがいっぱいで、実行中のスレッドの数がmaximumPoolSize以上の場合、スレッドプールは例外をスローし、呼び出し元に「タスクを受け入れることができなくなりました」と通知します。
  3. スレッドがタスクを完了すると、実行のためにキューから次のタスクが削除されます。
  4. スレッドが何の関係もなく、一定の時間(keepAliveTime)を超えると、スレッドプールは、現在実行中のスレッドの数がcorePoolSizeより大きい場合、このスレッドは停止すると判断します。したがって、スレッドプールのすべてのタスクが完了すると、最終的にはcorePoolSizeのサイズに縮小されます。



遺言執行者

ツール

スレッドプールを作成する本質は、次のようにThreadPoolExecutorを生成することです。

newFixedThreadPool

 

public static ExecutorService newSingleThreadExecutor(){

    新しいFinalizableDelegatedExecutorService(new ThreadPoolExecutor(1、1、0L、TimeUnit.MILLISECONDS、new LinkedBlockingQueue <Runnable>()));を返します。

}

 

newFixedThreadPool

 

public static ExecutorService newFixedThreadPool(int nThreads){

    新しいThreadPoolExecutor(nThreads、nThreads、0L、TimeUnit.MILLISECONDS、new LinkedBlockingQueue <Runnable>());を返します。

}

 

newCachedThreadPool

 

public static ExecutorService newCachedThreadPool(){

    新しいThreadPoolExecutor(0、Integer.MAX_VALUE、60L、TimeUnit.SECONDS、new SynchronousQueue <Runnable>());を返します。

}

  • newCachedThreadPoolコアスレッドの数は0
    で、キャッシュ可能なスレッドプールをキャッシュできます。スレッドプールの長さが処理要件を超える場合は、アイドル状態のスレッドを柔軟にリサイクルできます。リサイクルがない場合は、新しいスレッドを作成できます。スレッドプールはInteger.MAX_VALUEサイズです。2番目のタスクが実行されると、最初のタスクが完了し、最初のタスクを実行するスレッドは、毎回新しいスレッドを作成する代わりに再利用されます。
  • newFixedThreadPool
    固定長スレッドプール、コアスレッドの数、およびスレッドの最大数は同じサイズです。最大同時スレッド数を制御でき、超過スレッドはキューで待機します。固定長スレッドプールのサイズは、Runtime.getRuntime()。availableProcessors()などのシステムリソースに応じて最適に設定されます。
  • newSingleThreadExecutor
    は、シングルスレッドスレッドプールを作成します。タスクの実行には単一のワーカースレッドのみを使用し、すべてのタスクが指定された順序(FIFO、LIFO、優先度)で実行されるようにします。
  • newScheduledThreadPool
    は、固定長のスレッドプールを作成して、タイミングと定期的なタスクの実行をサポートします。
  • パブリッククラスT_ScheduledPool {
  •  
  •     public static void main(String [] args){
  •         ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
  •  
  •         service.scheduleAtFixedRate(()-> {
  •  
  •             {を試してください
  •                 TimeUnit.MILLISECONDS.sleep(new Random()。nextInt());
  •             } catch(InterruptedException e){
  •                 e.printStackTrace();
  •             }
  •  
  •             System.out.println(Thread.currentThread()。getName());
  •  
  •         }、0,500、TimeUnit.MILLISECONDS);
  •     }
  • }
  • ScheduledExecutorServiceはExecutorServiceを継承します

 

 

  • パブリッククラスT_ScheduledPool {
  •  
  •     public static void main(String [] args){
  •         ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
  •  
  •         service.scheduleAtFixedRate(()-> {
  •  
  •             {を試してください
  •                 TimeUnit.MILLISECONDS.sleep(new Random()。nextInt());
  •             } catch(InterruptedException e){
  •                 e.printStackTrace();
  •             }
  •  
  •             System.out.println(Thread.currentThread()。getName());
  •  
  •         }、0,500、TimeUnit.MILLISECONDS);
  •     }
  • }
  • ScheduledExecutorServiceはExecutorServiceを継承します

 

 

 

 

おすすめ

転載: blog.csdn.net/huzhiliayanghao/article/details/106816445