ホームページ  >  記事  >  Java  >  Javaはスレッドプールをどのように使用しますか?コード。

Javaはスレッドプールをどのように使用しますか?コード。

WBOY
WBOY転載
2023-05-08 14:31:071845ブラウズ

Java スレッド プールの中心原則

Java スレッド プールのソース コードを読んだことのある人は誰でも、Java スレッド プールのコア クラスが ThreadPoolExecutor であり、ThreadPoolExecutor クラスのコア構築メソッドが次のことを行っていることを知っています。以下に示すように、7 つのパラメータを持つコンストラクター メソッドがあります。

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

各パラメータの意味は以下のとおりです。

  • corePoolSize: スレッド プール内の常駐コア スレッドの数。

  • maximumPoolSize: スレッド プールは、同時に実行するスレッドの最大数を収容できます。この値は 1 以上です。

  • keepAliveTime: 過剰なアイドル スレッドの生存時間スペース時間が keepAliveTime 値に達すると、corePoolSize スレッドのみが残るまで、過剰なスレッドは破棄されます。

  • unit: keepAliveTime の単位。

  • workQueue: タスク キュー、送信されたがまだ実行されていないタスク。

  • threadFactory: スレッド プールにワーカー スレッドを生成するスレッド ファクトリを表します。ユーザーが新しいスレッドを作成する場合、通常はデフォルトで十分です。

  • handler: 拒否戦略。スレッド キューがいっぱいで、ワーカー スレッドがスレッド プールの最大表示数以上である場合に、実行可能なリクエストの実行戦略を拒否する方法を示します。 (最大プールサイズ)。

Java のスレッド プールは、プロデューサー/コンシューマー モデル を通じて実装されており、スレッド プールのユーザーがプロデューサーであり、スレッド プール自体がコンシューマーです。 。

Java スレッド プールのコア ワークフローを次の図に示します。

Javaはスレッドプールをどのように使用しますか?コード。

Java スレッド プールの実践

手動で実装したスレッド プールは、Java 独自のスレッド プールよりもはるかに単純です。あらゆる種類の複雑さを取り除きました。このメソッドは、スレッド プールのユーザーがタスク キューにタスクを追加し、スレッド プール自体がタスク キューからタスクを消費してタスクを実行するという中心原則のみを保持します。

Javaはスレッドプールをどのように使用しますか?コード。

この中心原則を理解していれば、次のコードははるかに簡単になります。この単純なスレッド プールを実装する場合、実装プロセス全体を解体できます。分解された実装プロセスは、コア フィールドの定義、内部クラス WorkThread の作成、ThreadPool クラスのコンストラクターの作成、およびタスクを実行するメソッドの作成です。

コア フィールドの定義

まず、ThreadPool という名前の Java クラスを作成し、このクラスに次のコア フィールドを定義します。

  • DEFAULT_WORKQUEUE_SIZE: デフォルトのブロッキング キュー サイズを示す静的定数。

  • workQueue: ブロッキング キューを使用して実際のスレッド プールをシミュレートし、プロデューサー/コンシューマー モデルを実装します。

  • workThreads: 実際のスレッド プールをシミュレートし、List コレクションを使用してスレッド プール内の作業スレッドを保存します。

コアコードは次のとおりです。

//默认阻塞队列大小
private static final int DEFAULT_WORKQUEUE_SIZE = 5;

//模拟实际的线程池使用阻塞队列来实现生产者-消费者模式
private BlockingQueue<Runnable> workQueue;

//模拟实际的线程池使用List集合保存线程池内部的工作线程
private List<WorkThread> workThreads = new ArrayList<WorkThread>();

内部クラス WordThread の作成

スレッド プール内のワーカー スレッドをシミュレートするために、ThreadPool クラスに内部クラス WorkThread を作成します。主な機能は、workQueue 内のタスクを消費し、タスクを実行することです。ワーカー スレッドは workQueue から継続的にタスクを取得する必要があるため、ここでは while (true) ループを使用してキュー内のタスクを継続的に消費しようとします。

コアコードは次のとおりです。

//内部类WorkThread,模拟线程池中的工作线程
//主要的作用就是消费workQueue中的任务,并执行
//由于工作线程需要不断从workQueue中获取任务,使用了while(true)循环不断尝试消费队列中的任务
class WorkThread extends Thread{
    @Override
    public void run() {
        //不断循环获取队列中的任务
        while (true){
            //当没有任务时,会阻塞
            try {
                Runnable workTask = workQueue.take();
                workTask.run();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

ThreadPool クラスのコンストラクターの作成

ここでは、ThreadPool クラスのコンストラクターを 2 つ作成します。1 つのコンストラクターには、スレッド プールの容量とブロッキング キューが渡され、他のコンストラクターでは、スレッド プールの容量のみが渡されます。

コアコードは次のとおりです。

//在ThreadPool的构造方法中传入线程池的大小和阻塞队列
public ThreadPool(int poolSize, BlockingQueue<Runnable> workQueue){
    this.workQueue = workQueue;
    //创建poolSize个工作线程并将其加入到workThreads集合中
    IntStream.range(0, poolSize).forEach((i) -> {
        WorkThread workThread = new WorkThread();
        workThread.start();
        workThreads.add(workThread);
    });
}

//在ThreadPool的构造方法中传入线程池的大小
public ThreadPool(int poolSize){
    this(poolSize, new LinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE));
}

タスクを実行するメソッドを作成する

ThreadPool クラスにタスクを実行するメソッドを作成します。execute() メソッドの実装は比較的単純で、メソッドによって受信された実行可能なタスクが workQueue キューに追加されます。

コアコードは次のとおりです。

//通过线程池执行任务
public void execute(Runnable task){
    try {
        workQueue.put(task);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

完全なソース コード

ここでは、以下に示すように、手動で実装された ThreadPool スレッド プールの完全なソース コードを提供します。

package io.binghe.thread.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.IntStream;

/**
 * @author binghe
 * @version 1.0.0
 * @description 自定义线程池
 */
public class ThreadPool {

    //默认阻塞队列大小
    private static final int DEFAULT_WORKQUEUE_SIZE = 5;

    //模拟实际的线程池使用阻塞队列来实现生产者-消费者模式
    private BlockingQueue<Runnable> workQueue;

    //模拟实际的线程池使用List集合保存线程池内部的工作线程
    private List<WorkThread> workThreads = new ArrayList<WorkThread>();

    //在ThreadPool的构造方法中传入线程池的大小和阻塞队列
    public ThreadPool(int poolSize, BlockingQueue<Runnable> workQueue){
        this.workQueue = workQueue;
        //创建poolSize个工作线程并将其加入到workThreads集合中
        IntStream.range(0, poolSize).forEach((i) -> {
            WorkThread workThread = new WorkThread();
            workThread.start();
            workThreads.add(workThread);
        });
    }

    //在ThreadPool的构造方法中传入线程池的大小
    public ThreadPool(int poolSize){
        this(poolSize, new LinkedBlockingQueue<>(DEFAULT_WORKQUEUE_SIZE));
    }

 //通过线程池执行任务
    public void execute(Runnable task){
        try {
            workQueue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //内部类WorkThread,模拟线程池中的工作线程
    //主要的作用就是消费workQueue中的任务,并执行
    //由于工作线程需要不断从workQueue中获取任务,使用了while(true)循环不断尝试消费队列中的任务
    class WorkThread extends Thread{
        @Override
        public void run() {
            //不断循环获取队列中的任务
            while (true){
                //当没有任务时,会阻塞
                try {
                    Runnable workTask = workQueue.take();
                    workTask.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

はい、Java スレッド プールの最小限のバージョンを実装するために、数十行の Java コードを使用しただけです。はい、この最小限のバージョンの Java スレッド プールのコードは、Java スレッド プールを具体化しています。中心原則。

次に、この最小限のバージョンの Java スレッド プールをテストしてみましょう。

テスト プログラムの作成

テスト プログラムも比較的単純です。つまり、main() メソッドで ThreadPool クラスのコンストラクターを呼び出し、スレッド プールのサイズを渡します。そして、ThreadPool クラスのインスタンスを作成します。その後、ThreadPool クラスのexecute() メソッドがループ内で 10 回呼び出され、スレッド プールに送信されるタスクは次のようになります: 現在のスレッドの名前を出力します-- ->> こんにちは、ThreadPool

全体的なテストコードは次のとおりです。

package io.binghe.thread.pool.test;

import io.binghe.thread.pool.ThreadPool;

import java.util.stream.IntStream;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试自定义线程池
 */
public class ThreadPoolTest {

    public static void main(String[] args){
        ThreadPool threadPool = new ThreadPool(10);
        IntStream.range(0, 10).forEach((i) -> {
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "--->> Hello ThreadPool");
            });
        });
    }
}

次に、ThreadPoolTestクラスのmain()メソッドを実行すると、以下の情報が出力されます。

スレッド-0--->>こんにちは、ThreadPool
Thread-9--->>こんにちは、ThreadPool
Thread-5--->>こんにちは、ThreadPool
Thread-8--->>こんにちは、ThreadPool
Thread-4--->>こんにちは、ThreadPool
Thread-1--->>こんにちは、ThreadPool
Thread-2--->>こんにちは、ThreadPool
Thread-5--->>こんにちは、ThreadPool
Thread-9--->>こんにちは、ThreadPool
Thread-0--->>こんにちは、スレッドプール

以上がJavaはスレッドプールをどのように使用しますか?コード。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。