Javaの4種類のよく使うスレッドの池の詳しい紹介


一.スレッド池概要
1.スレッド池の概念:
スレッド池は最初にいくつかのスレッドを作成し、それらの集合をスレッド池と呼ぶ。スレッドプールを使用するとパフォーマンスが良くなり、スレッドプールはシステム起動時に大量の空きスレッドを作成し、プログラムはスレッドプールに転送され、スレッドプールはスレッドを起動してこのタスクを実行します。実行が終了すると、スレッドは死なず、再びスレッドプールに戻って空き状態となり、次のタスクを実行するのを待ちます。
2.スレッド池の動作メカニズム
2.1オンラインプログラムのプログラムモードでは、スレッド全体に提出して、直接にスレッドに提出するのではなく、スレッドプールはタスクを取得した後、内部に空きスレッドがあるかどうかを探します。もしあれば、タスクをあるアイドルスレッドに渡すことができます。
2.2スレッドは同時に一つのタスクしか実行できませんが、同時に一つのスレッドプールに複数のタスクを提出することができます。
3.スレッド池を使う理由:
マルチスレッドの実行時間は、システムの継続的な起動と新しいスレッドの閉鎖によって、コストが非常に高く、システムリソースの遷移と移行スイッチングスレッドの危険性があり、システムリソースの崩壊を引き起こす可能性があります。この時、スレッド池は一番いい選択です。
二.四種類のよくあるスレッド池の詳細解
1.スレッド池の戻り値ExectorService概要:ExecutorServiceは、Javaが提供する管理スレッド池のクラスである。このクラスの2つの役割:スレッドの数を制御し、スレッドを再使用する。
2.具体的には4種類のよく使われるスレッド池が以下の通り実現されています。
2.1 Executors.newCacheThreadPool():キャッシュスレッド池は、先に池の中に以前に確立されたスレッドがあるかどうかを確認し、あればそのまま使用する。ない場合、新しいスレッドを作ってプールに参加します。キャッシュ型のプールは通常、生存期間が短い非同期型のタスクを実行するために使われます。
サンプルコード:

package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
   //          
   ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
   for (int i = 0; i < 10; i++) {
     try {
       //sleep                   ,        
       Thread.sleep(1000);
     } catch (InterruptedException e) {
       e.printStackTrace();
      }
     cachedThreadPool.execute(new Runnable() {
       public void run() {
    //             
          System.out.println(Thread.currentThread().getName()+"     ");
       }
      });
    }
  }
}
出力結果:
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-1が実行されています。
スレッドプールは無限大であり、現在のタスクを実行すると前のタスクが完了しています。スレッドを新規作成するたびに、前のタスクを実行するスレッドが多重されます。
2.2  Executors.newFixedThreadPool(int n):固定個数を再利用できるスレッド池を作成し、共有する非境界キュー方式でこれらのスレッドを実行する。
サンプルコード:

package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
    //               
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
     fixedThreadPool.execute(new Runnable() {
        public void run() {
          try {
           //             
           System.out.println(Thread.currentThread().getName()+"     ");
           Thread.sleep(2000);
         } catch (InterruptedException e) {
           e.printStackTrace();
          }
        }
     });
    }
  }
}
出力結果:
pool-1-thread-1が実行されています。
pool-1-thread-2が実行されています。
pool-1-thread-3が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-2が実行されています。
pool-1-thread-3が実行されています。
pool-1-thread-1が実行されています。
pool-1-thread-2が実行されています。
pool-1-thread-3が実行されています。
pool-1-thread-1が実行されています。
スレッドサイズは3なので、各ジョブはプリント結果を出力してからsleep 2秒で、2秒ごとに3つの結果をプリントします。
定长线程池の大きさはシステムリソースによって设定したほうがいいです。Runtime.getRuntime().availableProcessors()のようです
2.3  Executors.newScheduledThreadPool(int n):定長線プログラムを作成し、タイミングと周期性タスクの実行をサポートします。
遅延実行例コード:

package com.study.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
    //         ,            ――    
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    //  1   
    scheduledThreadPool.schedule(new Runnable() {
      public void run() {
        System.out.println("  1   ");
      }
    }, 1, TimeUnit.SECONDS);
   }
}
出力結果:
1秒遅れて実行
定期的に実行するコード例:

package com.study.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
  public static void main(String[] args) {
    //         ,            ――    
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    //  1   3     
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
       public void run() {
        System.out.println("  1   3     ");
      }
    }, 1, 3, TimeUnit.SECONDS);
  }
}
出力結果:
1秒遅れたら3秒ごとに一回実行します。
1秒遅れたら3秒ごとに一回実行します。
……
2.4  Executors.newSingleThreadExecutor():ワンライン程化されたスレッド池を作成し、それは唯一のワークスレッドでのみタスクを実行し、すべてのタスクが指定された順序(FIFO、LIFO、優先度)で実行されることを保証する。
サンプルコード:

package com.study.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThreadPoolExecutor {
  public static void main(String[] args) {
    //            
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
      final int index = i;
       singleThreadExecutor.execute(new Runnable() {
        public void run() {
          try {
            //      ,           
            System.out.println(Thread.currentThread().getName()+"     ,     :"+index);
            Thread.sleep(1000);
          } catch (InterruptedException e) {
             e.printStackTrace();
          }
        }
       });
    }
   }
}
出力結果:
pool-1-thread-1が実行されています。印刷の値は:0です。
pool-1-thread-1が実行されています。印刷の値は:1
pool-1-thread-1が実行されています。印刷の値は:2です。
pool-1-thread-1が実行されています。印刷の値は:3
pool-1-thread-1が実行されています。印刷の値は4です。
pool-1-thread-1が実行されています。印刷の値は:5です。
pool-1-thread-1が実行されています。印刷の値は:6です。
pool-1-thread-1が実行されています。印刷の値は:7です。
pool-1-thread-1が実行されています。印刷の値は:8です。
pool-1-thread-1が実行されています。印刷の値は:9です。
三.バッファキューBlocking Queとカスタムスレッド池ThreadPool Exector
1.バッファキューBlockingQue概要:
BlockingQueはダブルバッファです。BlockingQue内部は2つの列を使用して、2つのスレッドが同時に列に格納され、1つの取り出し操作が可能です。同時に安全を確保するとともに、行列のアクセス効率を向上させました。
2.よく使ういくつかのBlockingQue:
  • ArayBlocking Que(int i):サイズを決めたBlockingQueの構造はサイズを指定しなければなりません。これらのオブジェクトはFIFO順序で並べ替えられている。
  • Linked BlockingQue():サイズが不定のBlockingQueであれば、その構造時にサイズを指定し、生成されたBlockingQueはサイズ制限があり、サイズを指定しない。サイズはInteger.MAX_がある。VALEで決定します。これらのオブジェクトはFIFO順序で並べ替えられている。
  • PriorityBlocking Que()または(int i):Linked BlockingQueに類似していますが、その対象の順序はFIFOではなく、対象の自然の順序または構造関数のCompratorによって決定されます。
  • SynchronizedQue():特別なBlockingQueは、その操作に対しては、置いて、取って交替して完成しなければなりません。
  • 3.カスタムスレッド池(ThreadPool ExectorとBlockingQue接続):
    カスタムスレッドプールは、ThreadPoolExectorクラスで作成できます。複数の構成方法でスレッドを作成します。
    一般的な構造関数:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)サンプルコード:
    
    package com.study.test;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    class TempThread implements Runnable {
      @Override
      public void run() {
        //              
        System.out.println(Thread.currentThread().getName() + "     ");
         try {
          // sleep    3       3      
          Thread.sleep(1000);
         } catch (InterruptedException e) {
           e.printStackTrace();
        }
       } 
    }
    public class TestThreadPoolExecutor {
      public static void main(String[] args) {
        //            
        BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);
        // ThreadPoolExecutor:        ,         3,         6
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 6, 50, TimeUnit.MILLISECONDS, bq);
        //   3   
         Runnable t1 = new TempThread();
         Runnable t2 = new TempThread();
         Runnable t3 = new TempThread();
         // Runnable t4 = new TempThread();
         // Runnable t5 = new TempThread();
         // Runnable t6 = new TempThread(); 
         // 3       3      
         tpe.execute(t1);
         tpe.execute(t2);
         tpe.execute(t3);
         // tpe.execute(t4);
         // tpe.execute(t5);
         // tpe.execute(t6); 
         //         
         tpe.shutdown();
       }
    }
    出力結果:
    pool-1-thread-1が実行されています。
    pool-1-thread-2が実行されています。
    pool-1-thread-3が実行されています。
    締め括りをつける
    以上はこの文章の全部の内容です。本文の内容は皆さんの学習や仕事に対して一定の参考学習価値を持ってほしいです。ありがとうございます。もっと知りたいなら、下のリンクを見てください。