线程池之ThreadPoolExecutor

线程池构造参数

corePoolSize

核心线程池大小:如果任务进来,当前Worker数量小于corePoolSize则直接启动一个新的Worker进行作业

maximumPoolSize

第一次看到这个参数配置时错误的理解为:如果Worker数=corePoolSize,此时又有新任务提交到线程池,并且当前Worker数<maximumPoolSize,则立马启动新的Worker进行作业。
too young too simple,这个理解是错误的。。。

最大线程池大小:新任务提交至线程池,当前Worker数量超过corePoolSize大小,则会放入队列,如果队列也已经满了,此时再去判断当前Worker数量是否超过maximumPoolSize大小,如果否则创建新Worker进行作业

keepAliveTime

与参数TimeUnit共用,当线程池空闲时,对于空闲的Worker保持活跃的时间。例如:10秒,Worker数超过corePoolSize时,如果空闲时间超过10秒则会回收Worker至corePoolSize大小

workQueue

工作队列,当Worker数

threadFactory

线程工厂

RejectedExecutionHandler

线程池跑满时对线程的拒绝处理接口

验证maximumPoolSize代码

线程池代码

package com.gallant.test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * threadpool
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class ThreadPool {

  public static void main(String[] args) {
    int corePoolSize = 3;
    int maximumPoolSize = 10;
    long keepAliveTime = 10;
    TimeUnit unit = TimeUnit.SECONDS;
    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
    RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, (r)-> new MyTask(), handler);
    for (int i = 0; i < 100; i++) {
      threadPoolExecutor.submit(() -> {});
      System.out.println(i+1 + ", queue size:"+threadPoolExecutor.getQueue().size());
    }
  }
}

任务代码

package com.gallant.test;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * task
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class MyTask extends Thread {

  private static final AtomicInteger CNT = new AtomicInteger();

  public MyTask() {
    super(null, null, "MyTask-" + CNT.getAndAdd(1));
  }

  @Override
  public void run() {
    super.run();
    System.out.println(this.getName() + " is running");
    try {
      Thread.sleep(1000000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

执行结果


1, queue size:0
MyTask-0 is running
2, queue size:0
MyTask-1 is running
3, queue size:0
MyTask-2 is running
4, queue size:1
5, queue size:2
6, queue size:3
7, queue size:4
8, queue size:5
9, queue size:5
MyTask-3 is running
10, queue size:5
MyTask-4 is running
11, queue size:5
MyTask-5 is running
12, queue size:5
MyTask-6 is running
13, queue size:5
MyTask-7 is running
14, queue size:5
MyTask-8 is running
15, queue size:5
MyTask-9 is running
java.util.concurrent.FutureTask@7cc355be task is rejected
16, queue size:5
java.util.concurrent.FutureTask@6e8cf4c6 task is rejected
17, queue size:5

结论

3个核心Worker执行任务时,继续有任务进来时,放入队列,当队列满时(队列大小=5),才会继续增加新的Worker工作,直至Worker数量到达最大值时,如果仍然有任务进来,则执行拒绝处理接口来决策如何处理溢出的任务

验证keepAliveTime

线程池代码

package com.gallant.test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * threadpool
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class ThreadPool2 {

  public static void main(String[] args) {
    int corePoolSize = 3;
    int maximumPoolSize = 10;
    long keepAliveTime = 10;
    TimeUnit unit = TimeUnit.SECONDS;
    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
    RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, (r)-> new MyTask(), handler);
    for (int i = 0; i < 15; i++) {
      threadPoolExecutor.submit(() -> {});
    }
    for (int i = 0; i < 100000; i++) {
      System.out.println(i + 1 + " seconds, active count:" + threadPoolExecutor.getActiveCount()
          + " , completedTaskCount: " + threadPoolExecutor.getCompletedTaskCount() + ", poolSize:"
          + threadPoolExecutor.getPoolSize());
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

任务代码

package com.gallant.test;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * task
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class MyTask2 extends Thread {

  private static final AtomicInteger CNT = new AtomicInteger();

  public MyTask2() {
    super(null, null, "MyTask2-" + CNT.getAndAdd(1));
  }

  @Override
  public void run() {
    super.run();
    System.out.println(this.getName() + " is running");
  }
}

执行结果


MyTask2-0 is running
MyTask2-1 is running
MyTask2-2 is running
MyTask2-3 is running
MyTask2-4 is running
MyTask2-5 is running
MyTask2-6 is running
MyTask2-7 is running
MyTask2-8 is running
MyTask2-9 is running
1 seconds, active count:10 , completedTaskCount: 0, poolSize:10
2 seconds, active count:10 , completedTaskCount: 0, poolSize:10

与预期效果不同,为什么完成任务数量始终为0?明明我们的任务是立即就可以执行完成的

问题分析

线程池原理不多说,简而言之就是将任务封装为Worker进行执行,看下Worker的构造器

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

问题很明显了,由于我们重写了自定义的线程工厂接口的实现,使得线程池没有按照其原有的Worker模式执行,此时不会再执行Worker线程,因为我们的自定义工厂里面忽略target线程,也就是忽略了this(Worker),既然走不到Worker里面,也就不会出现在Worker执行完成时,将Worker从workers中移除,也就如我们所见,完成任务数始终为0,因为始终走不到下面的代码中。也就是说只添加了Worker,但是没有去执行Worker

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            ...
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

问题修复

修复后的代码如下:

package com.gallant.test;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * task
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class MyTask3 extends Thread {

  private static final AtomicInteger CNT = new AtomicInteger();

  public MyTask3(Runnable target) {
    super(null, target, "MyTask2-" + CNT.getAndAdd(1));
  }

  @Override
  public void run() {
    System.out.println(this.getName() + " is running");
    super.run();
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
package com.gallant.test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * threadpool
 *
 * @author : 会灰翔的灰机
 * @date : 2021/1/17
 */
public class ThreadPool3 {

  public static void main(String[] args) {
    int corePoolSize = 3;
    int maximumPoolSize = 10;
    long keepAliveTime = 10;
    TimeUnit unit = TimeUnit.SECONDS;
    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
    RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
        keepAliveTime, unit, workQueue, MyTask3::new, handler);
    new Thread(() -> {
      for (int i = 0; i < 100000; i++) {
        System.out.println(i + 1 + " seconds, active count:" + threadPoolExecutor.getActiveCount()
            + " , completedTaskCount: " + threadPoolExecutor.getCompletedTaskCount() + ", poolSize:"
            + threadPoolExecutor.getPoolSize());
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }).start();
    for (int i = 0; i < 15; i++) {
      threadPoolExecutor.submit(() -> {});
    }
  }
}

修复后执行结果


1 seconds, active count:0 , completedTaskCount: 0, poolSize:0
MyTask2-0 is running
MyTask2-1 is running
MyTask2-2 is running
MyTask2-3 is running
MyTask2-4 is running
2 seconds, active count:0 , completedTaskCount: 15, poolSize:5
3 seconds, active count:0 , completedTaskCount: 15, poolSize:5
4 seconds, active count:0 , completedTaskCount: 15, poolSize:5
5 seconds, active count:0 , completedTaskCount: 15, poolSize:5
6 seconds, active count:0 , completedTaskCount: 15, poolSize:5
7 seconds, active count:0 , completedTaskCount: 15, poolSize:5
8 seconds, active count:0 , completedTaskCount: 15, poolSize:5
9 seconds, active count:0 , completedTaskCount: 15, poolSize:5
10 seconds, active count:0 , completedTaskCount: 15, poolSize:5
11 seconds, active count:0 , completedTaskCount: 15, poolSize:3
12 seconds, active count:0 , completedTaskCount: 15, poolSize:3

结论

与我们期望相符,共计15个任务,有5个Worker便完成了所有任务,当所有Worker空闲时间大于配置的保持活跃时间(keepAliveTime,案例使用的配置为:10秒)时,则退出超出核心Worker数(corePoolSize)的空闲Worker,保持活跃的Worker数不低于核心Worker数配置(案例使用的配置为3)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值