Javaスレッドプールは、あなたが実際にそれを知っていますか?少し知識を行います! - 本を送信するために、テキストの終わり

オリジナルリンク: https://item.jd.com/12696168.html

トップをクリックして、[フルスタックの開発者コミュニティ]右上[...][]に設定⭐主演]640?

スレッドプールの利点

図1に示すように、スレッドは、各ワーカースレッドを再利用することができ、希少資源であり、数値のスレッドプールのスレッドの作成および破壊を使用低減することができます。

2は、システムの容量に応じて、彼らは、サーバーがクラッシュする消費あまりにも多くのメモリを防ぐために、スレッドプール内のワーカースレッドの数を調整します。

スレッドプールを作成します。

public ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler)
  • corePoolSize:コアスレッドプールスレッドの数

  • maximumPoolSize:スレッドプール内のスレッドの最大数

  • keepAliverTime:アクティブなスレッドの数は、スレッドのコア数、過剰アイドルスレッドの最大生存時間よりも大きいです

  • 単位:生存時間の単位

  • ワークキュー:タスクキューを保存します

  • ハンドラ:スコープスレッドおよびキューの容量を超えたハンドラタスク

スレッドプールの原則

スレッドプールのスレッドプールのプロセスにジョブをサブミットし、次のとおりです。

        図1に示すように、決定するスレッドプールのスレッドのコアのタスクの実装にするかどうか、そうでない場合は(コアのスレッドがアイドルであるか、またはスレッドが作成されないコアが存在しない)タスクを実行するための新規スレッドを作成するために取り組んでいます。コアスレッドがミッションにしている場合は、次のプロセスに入ります。

        作業キューが満杯でない場合は2、作業キューが一杯であるかどうかを判断するためのスレッド・プールは、タスクが新たに投入されたジョブキューに格納されます。作業キューがいっぱいになっている場合は、次のプロセスに入ります。

        決定する3、スレッドプールのスレッドが作業状態にある場合でない場合は、タスクを実行するために、新しいワーカースレッドを作成し、。完全な場合には、飽和戦略にこのタスクに対処します。

640?wx_fmt = JPEG

ソーススレッドプールを解釈

1、execute()メソッドのThreadPoolExecutor

public void execute(Runnable command) {
     if (command == null)
        throw new NullPointerException();
   //如果线程数大于等于基本线程数或者线程创建失败,将任务加入队列
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
    //线程池处于运行状态并且加入队列成功
        if (runState == RUNNING && workQueue.offer(command)) {
           if (runState != RUNNING || poolSize == 0)
             ensureQueuedTaskHandled(command);
          }
      //线程池不处于运行状态或者加入队列失败,则创建线程(创建的是非核心线程)
        else if (!addIfUnderMaximumPoolSize(command))
        //创建线程失败,则采取阻塞处理的方式
         reject(command); // is shutdown or saturated
      }
 }

図2に示すように、スレッド作成方法:addIfUnderCorePoolSize(コマンド)

private boolean addIfUnderCorePoolSize(Runnable firstTask) {
    Thread t = null;
     final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
     try {
         if (poolSize < corePoolSize && runState == RUNNING)
           t = addThread(firstTask);
    } finally {
        mainLock.unlock();
    }
     if (t == null)
        return false;
    t.start();
     return true;
}

私たちは、7行目のキーを見て:

private Thread addThread(Runnable firstTask) {
     Worker w = new Worker(firstTask);
     Thread t = threadFactory.newThread(w);
      if (t != null) {
        w.thread = t;
        workers.add(w);
         int nt = ++poolSize;
         if (nt > largestPoolSize)
           largestPoolSize = nt;
      }
      return t;
}

ここでは、スレッドパッケージは、ワーカースレッド、スレッドグループを操作し、作業工程クラスワーカーrunメソッドに配置します

public void run() {
     try {
       Runnable task = firstTask;
       firstTask = null;
       while (task != null || (task = getTask()) != null) {
           runTask(task);
            task = null;
        }
     } finally {
        workerDone(this);
     }
}

労働者のタスクを実行した後、チームはタスクがgetTaskメソッドサイクルによって実行されている動作するようになります。

私たちは、スレッドプールプログラムの作品を守ってください。

1、スレッドを作成

public class ThreadPoolTest implements Runnable
{
    @Override
    public void run()
    {
        try
        {
            Thread.sleep(300);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

2、16を実行しているスレッドプールスレッドループ:

public static void main(String[] args)
    {
        LinkedBlockingQueue<Runnable> queue =
            new LinkedBlockingQueue<Runnable>(5);
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, queue);
        for (int i = 0; i < 16 ; i++)
        {
            threadPool.execute(
                new Thread(new ThreadPoolTest(), "Thread".concat(i + "")));
            System.out.println("线程池中活跃的线程数:" + threadPool.getPoolSize());
            if (queue.size() > 0)
            {
                System.out.println("----------------队列中阻塞的线程数" + queue.size());
            }
        }
        threadPool.shutdown();
    }

結果:

线程池中活跃的线程数:1
线程池中活跃的线程数:2
线程池中活跃的线程数:3
线程池中活跃的线程数:4
线程池中活跃的线程数:5
线程池中活跃的线程数:5
----------------队列中阻塞的线程数1
线程池中活跃的线程数:5
----------------队列中阻塞的线程数2
线程池中活跃的线程数:5
----------------队列中阻塞的线程数3
线程池中活跃的线程数:5
----------------队列中阻塞的线程数4
线程池中活跃的线程数:5
----------------队列中阻塞的线程数5
线程池中活跃的线程数:6
----------------队列中阻塞的线程数5
线程池中活跃的线程数:7
----------------队列中阻塞的线程数5
线程池中活跃的线程数:8
----------------队列中阻塞的线程数5
线程池中活跃的线程数:9
----------------队列中阻塞的线程数5
线程池中活跃的线程数:10
----------------队列中阻塞的线程数5
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task Thread[Thread15,5,main] rejected from java.util.concurrent.ThreadPoolExecutor@232204a1[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
    at test.ThreadTest.main(ThreadTest.java:17)

結果から、観察することができます。

  1. 作成されたスレッドプールは、具体的に構成されたコア5のスレッドの数、すべてのスレッドの数は10であり、ワークキューの長さは5です。

  2. 我々は()のメソッドqueue.sizeにより、キュー内のタスクの数を取得するために働きます。

  3. 動作原理:

        あなたが新しいスレッドを作成している始めた後、5後のカーネルスレッドの数に、新しい割り当てが新しいスレッドを作成しますが、タスクキューの作業に参加しますもはや来る、キューは5行目にタスクに到達していない、と新しいタスク新しい共通のスレッドを作成し、スレッド10の最大数まで、スレッドプールは、後者のタスクは、飽和ポリシー構成に対処することです。私たちは、特定の構成を持っていない、デフォルトの設定が使用されているAbortPolicy:直接投げます。

        もちろん、私が欲しい効果を達成するために、タスク処理スレッド上で睡眠の使用​​は、スレッドが解放されません原因です!

RejectedExecutionHandler:飽和戦略

キューとスレッドプールは、スレッド・プールが飽和していることを示す、一杯になると、我々は処理のために提出され、新たなタスクのための特別な戦略を採用しなければなりません。この戦略は、それがスローされた新しいタスクを処理することができなかったと述べ、デフォルトの設定AbortPolicyです。JAVAは、戦略の4種類が用意されています。

  • AbortPolicy:直接スロー例外

  • CallerRunsPolicy:唯一のスレッド実行中のタスクの呼び出し

  • DiscardOldestPolicy:最近のタスクをキューイングし、現在のタスクを実行して捨てます。

  • DiscardPolicy:無治療、廃棄されました。

私たちは今、上記の手順に対処するための第四の戦略を持っています:

public static void main(String[] args)
    {
        LinkedBlockingQueue<Runnable> queue =
            new LinkedBlockingQueue<Runnable>(3);
        RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, queue,handler);
        for (int i = 0; i < 9 ; i++)
        {
            threadPool.execute(
                new Thread(new ThreadPoolTest(), "Thread".concat(i + "")));
            System.out.println("线程池中活跃的线程数:" + threadPool.getPoolSize());
            if (queue.size() > 0)
            {
                System.out.println("----------------队列中阻塞的线程数" + queue.size());
            }
        }
        threadPool.shutdown();
    }

結果

线程池中活跃的线程数:1
线程池中活跃的线程数:2
线程池中活跃的线程数:2
----------------队列中阻塞的线程数1
线程池中活跃的线程数:2
----------------队列中阻塞的线程数2
线程池中活跃的线程数:2
----------------队列中阻塞的线程数3
线程池中活跃的线程数:3
----------------队列中阻塞的线程数3
线程池中活跃的线程数:4
----------------队列中阻塞的线程数3
线程池中活跃的线程数:5
----------------队列中阻塞的线程数3
线程池中活跃的线程数:5
----------------队列中阻塞的线程数3

ここで採用戦略を廃棄した後、例外がスローされますが、廃棄されなくなりました。いくつかの重要な場面では、ロギングを使用してもよいし、データベースに保存されている、それは破棄すべきではありません。

ポリシーを設定する方法は2つあります。

最初:

RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, queue,handler);

第二:

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, queue);
threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());

 
            
 
 

おすすめ

転載: blog.csdn.net/weixin_35681869/article/details/102675198