JAVAマルチスレッドの4つの方法でのスレッドプールの詳細な分析
JAVAマルチスレッド4つの方法
javaでスレッドを実装する4つの方法:
- 1. Threadクラスを継承し、runメソッドをオーバーライドします
- 2. Runnableインターフェイスを実装し、runメソッドを実装します
- 3. Callableインターフェイスを継承してcallメソッドを実装し、futureTaskを使用して呼び出します(戻り値付き/例外を処理できます)
[上記の3つのタイプは通常のビジネスコードでは使用されません。]
[すべてのマルチスレッド非同期タスクは、実行のためにスレッドプールに引き渡される必要があります]
-
4.スレッドプール(スレッドの再利用、同時実行の最大数の制御、スレッドの管理)
-
リソース消費を削減する
- すでに作成されたスレッドを再利用することにより、スレッドの作成と破棄によって引き起こされる損失を減らします
-
応答速度を向上させる
- スレッドプール内のスレッド数が上限を超えていないため、一部のスレッドはタスクの割り当てを待機している状態であり、タスクが来ると、新しいスレッドを作成せずに実行できます。
-
スレッドの管理性を向上させる
- スレッドプールは、現在のシステムの特性に応じてプール内のスレッドを最適化し、スレッドの作成と破棄によって発生するシステムオーバーヘッドを削減します。スレッドのワイヤレス作成と破棄は、システムリソースを削減するだけでなく、システムの安定性も低下させ、均一性のためにスレッドプールを使用します。分布
-
1. Threadクラスを継承し、runメソッドをオーバーライドします
public class ThreadTest {
public static void main(String args[]){
System.out.println("main start ....");
// 1.继承Thread类 重写run方法
new Thread01().start();
System.out.println("main end ....");
}
public static class Thread01 extends Thread{
@Override
public void run() {
System.out.println("1.继承Thread类 重写run方法");
}
}
}
2. Runnableインターフェイスを実装し、runメソッドを実装します
public class ThreadTest {
public static void main(String args[]){
System.out.println("main start ....");
// 2.实现Runnable接口 实现run方法
new Thread(new Runnable01()).start();
System.out.println("main end ....");
}
public static class Runnable01 implements Runnable{
@Override
public void run() {
System.out.println("2.实现Runnable接口 实现run方法");
}
}
}
3. Callableインターフェイスを継承してcallメソッドを実装し、futureTaskを使用して呼び出します(戻り値付き/例外を処理できます)
public class ThreadTest {
public static void main(String args[]) throws ExecutionException, InterruptedException {
System.out.println("main start ....");
// 3.继承Callable接口 实现call方法 使用futureTask调用 (有返回值/可处理异常)
Callable01 callable01 = new Callable01();
FutureTask<Integer> futureTask = new FutureTask<>(callable01);
new Thread(futureTask).start();
//使用futureTask 获取返回值 会阻塞等待
System.out.println(futureTask.get());
System.out.println("main end ....");
}
public static class Callable01 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("3.继承Callable接口 实现call方法 使用futureTask调用 (有返回值/可处理异常)");
return new Integer(200);
}
}
}
4.スレッドプール
4.1基本的なスレッドプールの適用
public class ThreadTest {
//正常情况保证一个项目中只有少数线程池,每个异步任务,线程池让他自己取执行
//Executors.newFixedThreadPool(10); 使用工具类生成容量为10的线程池
//自定义线程池使用 new ThreadPoolExecutor(); 自定义七大参数
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String args[]){
System.out.println("main start ....");
try{
service.execute(()->{
System.out.println("4.线程池");
});
}catch (Exception e){
e.printStackTrace();
}finally{
service.shutdown();
}
System.out.println("main end ....");
}
}
4.2実行者補助ツール
Executors.newFixedThreadPool(int); //创建固定容量的线程池
Executors.newSingleThreadExecutor(); //创建一个只有1个工作线程的线程池
Executors.newCachedThreadPool() //创建一个可扩容的线程池。执行很多短期异步任务,线程池根据需要创建新线程,但在先前构造的线程可用时将重用他们。可扩容。
public class MyThreadPoolDemo {
public static void main(String args[]){
//固定容量的线程池
// ExecutorService threadPool =Executors.newFixedThreadPool(5); //创建一个有5个工作线程的线程池
// ExecutorService threadPool =Executors.newSingleThreadExecutor(); //创建一个只有1个工作线程的线程池
ExecutorService threadPool =Executors.newCachedThreadPool(); //创建一个可扩容的线程池
try{
for (int i = 1; i <10; i++) {
//从线程池中使用一个工作线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
}catch (Exception e){
}finally{
//任务结束 归还线程
threadPool.shutdown();
}
}
}
上記の3つのExecutorsAPIの最下層は、異なるパラメーターを持つThreadPoolExecutorを使用して実装されます。
4.3ThreadPoolExecutorの7つのパラメーターの分析
-
1.corePoolSize:スレッド内の常駐コアスレッドの数
-
2、maxmunPoolSize:スレッドプールで同時に実行できるスレッドの最大数。この値は1より大きくなければなりません。
-
3. KeepAliveTime:冗長なアイドルスレッドの存続時間。現在のプール内のスレッドの数がcorePoolSize &&を超え、アイドル時間がkeepAliveTimeに達すると、corePoolSizeスレッドが残るまで、余分なスレッドは破棄されます(過剰な戦略)
-
4.ユニット:keepAliveTimeユニット
-
5. workQueue:タスクブロッキングキュー、送信されたがまだ実行されていないタスク(十分な戦略がない)
-
6、threadFactory:スレッドプールでワーカースレッドを生成するスレッドファクトリを表し、スレッドの作成に使用されます。通常、デフォルトで問題ありません
-
7.ハンドラー:拒否戦略。これは、タスクブロッキングキューがいっぱいで、作業スレッドの総数がスレッドプール内のスレッドの最大数(maxmunPoolSize)以上の場合に、実行を要求された実行可能戦略(完全戦略)を拒否する方法を意味します。
4.4ThreadPoolExecutorの動作原理
-
1.スレッドプールを作成した後、リクエストの待機を開始します。
-
2. execute()メソッドを呼び出して要求タスクを追加すると、スレッドプールは次の判断を下します。
2.1実行中のスレッドの数がcorePoolSize未満の場合は、すぐにこのタスクを実行するスレッドを作成します。
2.2実行中のスレッドの数がcorePoolSize以上の場合、タスクをキューに入れます。
2.3この時点でキューがいっぱいで、実行中のスレッドの数がまだmaximumPoolSize未満の場合でも、このタスクをすぐに実行するには、非コアスレッドを作成する必要があります。
2.4キューがいっぱいで、実行中のスレッドの数がmaximumPoolSize以上の場合、スレッドプールは飽和拒否戦略を開始して実行します。
-
3.スレッドがタスクを完了すると、実行のためにキューから次のタスクが削除されます。
-
4.スレッドが一定期間(keepAliveTime)を超えて何の関係もない場合、スレッドは次のように判断します。
現在実行中のスレッドの数がcorePoolSizeより大きい場合、このスレッドは停止します。
したがって、スレッドプールのすべてのタスクが完了すると、最終的にはcorePoolSizeのサイズに縮小されます。
4.5カスタムスレッドプール
7つのパラメーターを使用してスレッドプールをカスタマイズします(最も重要なパラメーターは拒否戦略です)
public class MyThreadPoolDemo {
public static void main(String args[]){
ExecutorService threadPool = new ThreadPoolExecutor(2,
5,
2L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
}
4つの主要な拒否戦略:
1. ThreadPoolExecutor.AbortPolicy(); RejectExecutionExceptionを直接スローして、システムが正常に実行されないようにします。
2. ThreadPoolExecutor.CallerRunsPolicy();呼び出し元は調整メカニズムを実行します。この戦略は、タスクを放棄したり例外をスローしたりすることはありませんが、特定のタスクを呼び出し元に返すため、新しいタスクのフローが減少します。
3. ThreadPoolExecutor.DiscardOldestPolicy();キュー内で最も長く待機しているタスクを破棄してから、現在のタスクをキューに追加して、現在のタスクの送信を再試行します
4. ThreadPoolExecutor.DiscardPolicy();この戦略は、処理できないタスクをサイレントに破棄するか、タスクを処理しないか、例外をスローします。タスクが失われることが許されている場合、これが最善の戦略です。
メカニズム、この戦略はタスクを放棄したり例外をスローしたりすることはありませんが、特定のタスクを呼び出し元に返すため、新しいタスクのフローが減少します
3. ThreadPoolExecutor.DiscardOldestPolicy();キュー内で最も長く待機しているタスクを破棄してから、現在のタスクをキューに追加して、現在のタスクの送信を再試行します
4. ThreadPoolExecutor.DiscardPolicy();この戦略は、処理できないタスクをサイレントに破棄するか、タスクを処理しないか、例外をスローします。タスクが失われることが許されている場合、これが最善の戦略です。