ThreadPoolExecutor使用

ThreadPoolExecutor是 java提供的一个线程池工具类

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
 }


corePoolSize 最小线程数
maximumPoolSize 最大线程数

keepAliveTime  线程最大空闲时间 (当线程数大于 corePoolSize时,剩余的线程的空闲时间大于keepAliveTime将会被回收

unit   keepAliveTime对应的时间单位

workQueue 任务队列

threadFactory 线程工厂

handler  (饱和策略) 当线程数达到最大,且任务队列已满,就会调用 此handler的方法处理


默认情况下 不传入 threadFactory会提供一个默认的值,Executors.defaultThreadFactory()

不过默认的线程池名字是很揪心的,格式都是 pool-poolNumber-thread-threadNumber

所以要是创建了好几个线程池,名字基本就是pool-1-thread-1,pool-1-thread-2,  pool-2-thread-1, pool-2-thread-2,完全没有可读性

 DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }
google 的guava提供了一个方法设置线程池名称 new ThreadFactoryBuilder().setNameFormat("scheduler-pool-%d").build();  

这样一看就知道是什么线程了

如果不想引入google的guava,就自己写个类继承ThreadFactory,

public class MqThreadFactory implements ThreadFactory {

    private String poolName;
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    public MqAppThreadFactory(String poolName) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = poolName + "-pool" + "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
调用的时候传入poolName就行了

java提供了几种饱和策略供选择

AbortPolicy  当线程数达到最大,且任务队列已满,直接抛出异常,这也是ThreadPoolExecutor的默认饱和策略

DiscardPolicy 直接丢弃任务

DiscardOldestPolicy 丢弃队列里最近的一个任务,并执行当前任务

CallerRunsPolicy  只用用者所在线程来运行任 

threadPoolExecutor使用方式:

ExecutorService pool=new ThreadPoolExecutor(coreThreadSize, maxThreadSize,keepAliveTime, unit,
                queue, new MqThreadFactory(poolName)
这里使用默认的饱和策略


然后提交任务到线程池就行了
executorService.execute(new QueueHandler());

当然也可以调用 executorservice.submit 方法

提交到线程池的任务并不一定会马上执行,之前碰到一个问题,线程的代码默认监听BlockingQueue,

希望提高性能,所以项目初始化的时候,循环调用execute方法,希望线程池中的所有线程默认都开启,

结果发现,线程数维持在,corePoolSize,

下面是execute方法的执行流程:

1、线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作
线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这
个工作队列里。如果工作队列满了,则进入下个流程。
3、线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程
来执行任务。如果已经满了,则交给饱和策略来处理这个任务

具体的大家可以看看 java并发编程的艺术 这本书,个人觉得在某些细节上面讲的比  java并发编程实战要好


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值