ThreadPoolExecutor线程池使用

简介

线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。—来自百度百科

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue) {
   this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
        Executors.defaultThreadFactory(), defaultHandler);
}

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

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:空闲的多余线程保持时间,临时线程不执行任务时能够存活的时间;
  • TimeUnit:时间单位
  • BlockingQueue:阻塞式队列,正式线程都忙时将线程放到workQueue中,workQueue大小是n。
  • ThreadFactory:当线程池需要新的线程时,会使用ThreadFactory来生成新的线程。
  • RejectedExecutionHandler:由于线程无法接收你所提交的任务的拒绝策略。

线程添加策略

  • 在线程池刚创建出来时,线程池中没有任何线程,当有任务提交过来时,如果线程池中管理的线程的数量小于corePoolSize,则无论是否有闲置的线程都会创建新的线程来使用.而当线程池中管理的线程的数量达到了corePoolSize,再有新任务过来时,会复用闲置的线程。
  • 当所有的核心池大小中的线程都在忙碌,则再有任务提交,会存入workQueue中,进行排队,当核心池大小中的线程闲置后,会自动从workQueue获取任务执行。
  • 而当所有的核心池大小中的线程都在忙碌,workQueue也满了,则会再去创建新的临时线程来处理提交的任务,但是,无论如何,总的线程数量,不允许超过maximumPoolSize。
  • 而当所有的核心池大小中的线程都在忙碌,workQueue也满了,也创建了达到了maximumPoolSize的临时线程,再有任务提交,此时会交予RJHandler来拒绝该任务。
  • 当任务高峰过去,workQueue中的任务也都执行完成,线程也依次闲置了下来,则在此时,会将闲置时间超过keepAliveTime(单位为unit)时长的线程关闭掉,但是关闭时会至少保证线程池中管理的线程的数量 不少于corePoolSize个。

提交任务

execute

只能提交Runnable类型的任务,无返回值。在执行任务时,如果遇到异常会直接抛出。

ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
threadPoolExecutor.execute(()->{
    log.info("executorService test");
});

submit

既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。
submit在执行任务时,如果遇到异常不会直接抛出,只有在使用Future的get方法获取返回值时,才会抛出异常。

Future<?> submit_method = executorService.submit(new Runnable() {
    @Override
        public void run() {
            log.info("submit Runnable 。。。");
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    try {
        Object o = submit_method.get();//检查线程是否执行完成,未完成时阻塞
        log.info("submi Runnable is over, return ={}", o);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
Future<String> submit = executorService.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            log.info("submit Callable 。。。");
            Thread.sleep(3000L);
            return "ok";
        }
    });
    try {
        String s = submit.get();
        log.info("submit Callable is over, return={}", s);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

执行结果
在这里插入图片描述

invokeAny

场景:启动多个线程,相互独立的(无同步)去计算一个结果,当某一个线程得到结果之后,立刻终止所有线程,因为只需要一个结果就够了。
invokeAny()定义在AbstractExecutorService抽象类中,接收的参数是一个List,List中的每一个元素必须实现Callable接口。他的功能是依此启动新的线程执行List中的任务,并将第一个得到的结果作为返回值,然后立刻终结所有的线程。其用法如下:

List<Callable<String>> callables = new ArrayList<>();
callables.add(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(3000L);
        return "任务1";
    }
});

callables.add(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000L);
        return "任务2";
    }
});
try {
    String s = threadPoolExecutor.invokeAny(callables);
    log.info(s);
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

执行结果
在这里插入图片描述

invokeAll

阻塞式,必须等待所有任务执行完成后统一返回,可以设置超时时间,这里的超时时间是针对的所有tasks,而不是单个task的超时时间。如果超时,会取消没有执行完的所有任务,并抛出超时异常。相当于将每一个future的执行情况用一个list集合保存,当调用future.get()方法取值时和设置的timeout比较,是否超时。
这里提交的任务容器列表和返回的Future列表存在顺序对应的关系。
源码
在这里插入图片描述

try {
    List<Future<String>> futures = threadPoolExecutor.invokeAll(callables);
    futures.stream().forEach(f -> {
        try {
            log.info("获取结果、、、");
            log.info(f.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    });
} catch (Exception e) {
    e.printStackTrace();
}

try {
    List<Future<String>> futures = threadPoolExecutor.invokeAll(callables, 1000, TimeUnit.MILLISECONDS);
    futures.stream().forEach(f -> {
        try {
            log.info("获取结果、、、");
            log.info(f.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    });
} catch (Exception e) {
    e.printStackTrace();
}

执行结果
在这里插入图片描述

shutdown

将线程池状态置为SHUTDOWN。平滑的关闭ExecutorService,当此方法被调用时,ExecutorService停止接收新的任务并且等待已经提交的任务(包含提交正在执行和提交未执行)执行完成。当所有提交任务执行完毕,线程池即被关闭。

shutdownNow

将线程池状态置为STOP。跟shutdown()一样,先停止接收外部提交的任务,忽略队列里等待的任务,尝试将正在跑的任务interrupt中断,返回未执行的任务列表。

isShutdown

当调用shutdown()或shutdownNow()方法后返回为true。

isTerminated

当调用shutdown()方法后,并且所有提交的任务完成后返回为true;
当调用shutdownNow()方法后,成功停止后返回为true;

awaitTermination

接收timeout和TimeUnit两个参数,用于设定超时时间及单位。当等待超过设定时间时,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。

停止线程池

/**
 * 停止线程池
 * 先使用shutdown,停止接收新的任务并尝试完成所有已存在的任务。
 * 如果超时,则调用shutdownNow,取消在workQueue中Pending的任务,并中断所有阻塞函数。
 * 如果仍然超时,则强制退出。
 * 另外在shutdown时线程本身被调用中断做了处理
 * @param pool
 */
public static void shutdownAndAwaitTermination(ExecutorService pool) {
    if (pool != null && !pool.isShutdown()) {
        pool.shutdown();
        try {
            if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
                    log.info("pool did not termination");
                }
            }
        } catch (InterruptedException e) {
            pool.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值