ホームページ  >  記事  >  Java  >  Javaスレッドプールの詳しい説明

Javaスレッドプールの詳しい説明

angryTom
angryTom転載
2019-11-26 15:05:413309ブラウズ

Javaスレッドプールの詳しい説明

#スレッド プールの概要

1. スレッド プールは、スレッドを管理するプールであり、作成を削減できます。スレッドの破棄によりリソースが消費されます。

スレッドは実際にはオブジェクトであるため、オブジェクトを作成するには、クラスの読み込みプロセスを経て、オブジェクトを破棄し、GC ガベージを経る必要があります。収集プロセスのすべてにリソースのオーバーヘッドが必要です。

2. 応答速度の向上: タスクが到着したときに、スレッド プールからスレッドを取得する場合に比べ、自分でスレッドを作成する方が確実に遅くなります。使い終わったらスレッドをプールに戻し、再利用の効果を実現します


(推奨ビデオ:

java ビデオ チュートリアル

)

スレッド プールの実行

メタファーを作成するコア スレッドを会社の正規従業員と比較します

非コア スレッドを外注従業員と比較します

ブロッキング キューはデマンド プールと比較されます

タスクの送信は送信と比較されます要件

正式な実行Javaスレッドプールの詳しい説明

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
   BlockingQueue<Runnable> workQueue,
   ThreadFactory threadFactory,
   RejectedExecutionHandler handler)
corePoolSize     核心线程数
maximumPoolSize  线程池最大线程数
keepAliveTime    空闲线程存活时间
TimeUnit         线程空闲存活时间单位
workQueue        存放任务的阻塞队列
threadFactory    线程工厂
handler          饱和策略

● タスクを送信し、スレッド プール内に残っているコア スレッドの数がスレッド数 corePoolSize より少ない場合、スレッド プールは、送信されたタスクを処理するためのコア スレッドを作成します。 ## ● スレッド プール内のコア スレッドの数がいっぱいの場合、つまりスレッドの数が corePoolSize と等しい場合、新しく送信されたタスクはタスク キュー workQueue に置かれ、実行のためにキューに入れられます。

# スレッド プール内に残っているスレッドの数が corePoolSize と等しく、タスク キュー workQueue もいっぱいの場合、スレッドの数が MaximumPoolSize に達しているかどうか、つまりスレッドの最大数が 0 であるかどうかを判断します。そうでない場合は、非コアを作成します スレッドは、送信されたタスクを実行します。

# 現在のスレッド数がmaximumPoolSizeに達し、新しいタスクが来ると、拒否ポリシーが直接使用されます。

いくつかの飽和戦略

AbortPolicy         抛出一个异常,默认的
DiscardPolicy       直接丢弃任务
DiscardOldestPolicy 丢弃队列里最老的任务,将当前这个任务继续提交给线程池
CallerRunsPolicy    交给线程池调用所在的线程进行处理

スレッド プール例外処理

スレッド プール中にスレッド処理タスクが発生するためcall 例外はスレッド プールによってキャッチされる可能性があるため、タスクの実行が認識されない可能性があるため、スレッド プールの例外を考慮する必要があります。

方法 1:

@Test
public void test1() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 5; i++) {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("name: " + Thread.currentThread().getName());
                    Object a = null;
                    System.out.println(a.hashCode());
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        });
    }
}

方法 2:

@Test
public void test2() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 20; i++) {
        Future<?> future = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("name: " + Thread.currentThread().getName());
                Object a = null;
                System.out.println(a.hashCode());
            }
        });
        try {
            future.get();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

スレッド プール ワーク キュー

● ArrayBlockingQueue

● LinkedBlockingQueue#● SynchronousQueue

#● DelayQueue

#● PriorityBlockingQueue

==ArrayBlockingQueue==

● 特定の配列を初期化します。容量

# 再入可能なロックを使用します。デフォルトでは不公平なロックが使用されます。エンキューとデキューは同じロックを共有します。相互排他

# は制限された設計です。容量がいっぱいの場合、要素は使用できません。要素が削除されるまで追加される

# 使用する場合は、連続メモリを開放してください 初期化容量が大きすぎるとリソースの無駄が発生しやすくなります 小さすぎるとリソースの無駄が発生しやすくなります追加に失敗しました。

#==LinkedBlockingQueue==

● リンク リスト データ構造を使用します

#● 非連続メモリ空間

## ● 2 つのリエントラント ロックを使用します要素の入口と出口をそれぞれ制御し、Condition を使用してスレッド間のウェイクアップとデキューを行います。 Wait

● 境界あり、デフォルトのコンストラクターの容量は Integer.MAX_VALUE

==SynchronousQueue= =

#● 内部容量は 0

● すべての削除操作は挿入操作を待機する必要があります

##● すべての挿入操作は削除操作を待機する必要があります

# 要素の場合、挿入スレッドと削除スレッドが存在すると、すぐに挿入スレッドは削除スレッドに渡されます。このコンテナはチャネルに相当し、要素は格納されません

● マルチタスク キューでは、これがタスクを処理する最も速い方法です。

#==PriorityBlockingQueue==

#● 無制限の設計ですが、実際の容量はシステム リソースに依存します。

## ● 要素を追加し、複数の場合は優先順位を入力します

==DelayQueue==

● ボーダレスデザイン

#● 追加 (put) はブロックせず、ブロックを削除します

● 要素には有効期限があります

● 期限切れの要素のみが取り出されます

一般的に使用されるスレッド プール

● newFixedThreadPool (スレッド数が固定されたスレッド プール)

● newCachedThreadPool (スレッドをキャッシュできるスレッド プール)

#● newSingleThreadExecutor (シングル スレッド スレッド プール)

#● newScheduledThreadPool (スケジュールされた定期的な実行用のスレッド プール)

== newFixedThreadPool==

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

機能

1. コア スレッドの数は、スレッドの最大数と同じです

2.いわゆる非アイドル時間、つまり keepAliveTime は 0

3 です。ブロッキング キューは無制限のキューです LinkedBlockingQueue

動作メカニズム:

#● タスクの送信

##● スレッド数がコア スレッドより少ない場合は、タスクを実行するためのコア スレッドを作成します

● スレッド数がコア スレッドと等しい場合、タスクを LinkedBlockingQueue ブロッキング キューに追加します

● 如果线程执行完任务,去阻塞队列取任务,继续执行。

==newCachedThreadPool==

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

线程池特点

● 核心线程数为0

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是SynchronousQueue

● 非核心线程空闲存活时间为60秒

Javaスレッドプールの詳しい説明

工作机制:

● 提交任务

● 因为没有核心线程,所以任务直接加到SynchronousQueue队列。

● 判断是否有空闲线程,如果有,就去取出任务执行。

● 如果没有空闲线程,就新建一个线程执行。

● 执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。

使用场景

用于并发执行大量短期的小任务。

使用SynchronousQueue作为工作队列,工作队列本身并不限制待执行的任务的数量。但此时需要限定线程池的最大大小为一个合理的有限值,而不是Integer.MAX_VALUE,否则可能导致线程池中的工作者线程的数量一直增加到系统资源所无法承受为止。

如果应用程序确实需要比较大的工作队列容量,而又想避免无界工作队列可能导致的问题,不妨考虑SynchronousQueue。SynchronousQueue实现上并不使用缓存空间

==newSingleThreadExecutor==

线程池特点

● 核心线程数为1

● 最大线程数也为1

● 阻塞队列是LinkedBlockingQueue

● keepAliveTime为0

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

工作机制

Javaスレッドプールの詳しい説明

● 提交任务

● 线程池是否有一条线程在,如果没有,新建线程执行任务

● 如果有,讲任务加到阻塞队列

● 当前的唯一线程,从队列取任务,执行完一个,再继续取,一个人(一条线程)夜以继日地干活。

使用场景

适用于串行执行任务的场景,一个任务一个任务的执行

==newScheduledThreadPool==

线程池特点

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是DelayedWorkQueue

● keepAliveTime为0

● scheduleAtFixedRate() :按某种速率周期执行

● scheduleWithFixedDelay():在某个延迟后执行

工作机制

● 添加一个任务

● 线程池中的线程从 DelayQueue 中取任务

● 线程从 DelayQueue 中获取 time 大于等于当前时间的task

● 执行完后修改这个 task 的 time 为下次被执行的时间

● 这个 task 放回DelayQueue队列中

scheduleWithFixedDelay

● 无论任务执行时间长短,都是当第一个任务执行完成之后,延迟指定时间再开始执行第二个任务

scheduleAtFixedRate

● 在任务执行时间小于间隔时间的情况下,程序以起始时间为准则,每隔指定时间执行一次,不受任务执行时间影响

● 当执行任务时间大于间隔时间,此方法不会重新开启一个新的任务进行执行,而是等待原有任务执行完成,马上开启下一个任务进行执行。此时,执行间隔时间已经被打乱

本文来自php中文网,java教程栏目,欢迎学习!

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

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