【Java 线程池的使用】

前言

线程池创建方式

1、通过手动创建new FixedThreadPool()new SingleThreadExecutor()new CachedThreadPool()2、通过Executors.newFixedThreadPool()3、通过ThreadPoolExecutor构造方法创建线程池等

手动new和通过Executors创建返回对象都为ExecutorService

注:在《阿里巴巴java开发手册》中,不推荐newExecutors方式创建线程池,原因是因为有局限性,不灵活。推荐使用ThreadPoolExecutor创建线程池,更加符合规范和统一管理。

本章主要讲ThreadPoolExecutor,手动new和通过Executors如何创建以及其他详细在后面会单独出一章做详细介绍。

1、Java常用线程池

n为入参 待指定数值

线程池名称核心线程数最大线程数解释
FixedThreadPoolnn固定 线程池,核心线程数等于最大线程数
CachedThreadPool0Integer.MAX_VALUE缓存 线程池
SingleThreadPool11单线程 线程池
ScheduledThreadPoolnInteger.MAX_VALUE定时、周期性任务 线程池

2、Executors创建线程池常用方式

线程池名称解释
Executors.newFixedThreadPool()
Executors.newWorkStealingPool()
Executors.newCachedThreadPool()
Executors.newScheduledThreadPool()

3、ThreadPoolExecutor构造方法创建线程池

本章下面重点介绍
四种构造方法,这里选取参数最全的构造方法,相关参数会在下面介绍

    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

4、Executor框架

在介绍 ThreadPoolExecutor 之前,我们先介绍一下Executor框架。上一章中,我们介绍到通过 Runnable 接口和继承 Thread 类实现多线程编程时,会存在大量时间花费在线程的创建和销毁上,Executor 框架的引入就是来控制线程的创建、启动和销毁,简化多线程并发操作问题。

4.1、Executor继承关系图

在这里插入图片描述

4.2、Executor接口

从继承图中我们可以知道,Executor 接口是作为了 Executor 框架的顶级接口,其代码如下:

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

Executor 中只有一个方法,入参为 Runnable 对象。很明显的可以知道,该入参肯定是我们实现 Runnable 接口的对象,入参对象重写的 run() 方法则是我们实际需要处理的业务代码。

void execute(Runnable command);

4.3、ExecutorService接口

该接口继承了Executor接口,并增加了其他方法(主要是管理线程生命周期的方法)其源码如下:

public interface ExecutorService extends Executor {


    void shutdown();


    List<Runnable> shutdownNow();


    boolean isTerminated();


    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;


    <T> Future<T> submit(Callable<T> task);


    <T> Future<T> submit(Runnable task, T result);


    Future<?> submit(Runnable task);


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

   
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

   
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

   
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

作用方法名称解释
线程池关闭shutdown()不再接受新任务,直到所有子线程执行完才会真正关闭
shutdownNow()不再接受新任务,立马关闭
线程池是否关闭isShutdown()shutdown()被调用之后则为true
线程池是否终止isTerminated()任务执行完时才返回true
线程池是否关闭boolean awaitTermination(long timeout, TimeUnit unit)timeout超时时间,unit时间单位。每timeout/unit 判断一次是否关闭
任务提交的三种方式<T> Future<T> submit(Callable<T> task)任务对象 Callable接口实现类,返回Future对象
<T> Future<T> submit(Runnable task, T result)任务对象 Runnable接口实现类,future.get()返回 result
Future<?> submit(Runnable task)任务对象 Runnable接口实现类,future.get()返回 null
批量提交不限时任务。等待所有的任务执行完成后统一返回<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)可设置超时时间
取得第一个完成任务的结果值,当第一个任务执行完成后,会调用interrupt方法将其他的任务中断。<T> T invokeAny(Collection<? extends Callable<T>> tasks)
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)可设置超时时间

4.4、AbstractExecutorService类

我们主要讲的是通过 ThreadPoolExecutor (当然也可以通过Executors,下一篇文章会讲)来创建线程池,因此 继承图中的 ScheduledExecutorService 我们这里不再讲解。大家有兴趣的可以研究下该类源码。AbstractExecutorService 源码如下:

public abstract class AbstractExecutorService implements ExecutorService {


    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }


    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }


    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }


    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }


    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }


    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

        // For efficiency, especially in executors with limited
        // parallelism, check to see if previously submitted tasks are
        // done before submitting more of them. This interleaving
        // plus the exception mechanics account for messiness of main
        // loop.

        try {
            // Record exceptions so that if we fail to obtain any
            // result, we can throw the last exception we got.
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();

            // Start one task for sure; the rest incrementally
            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;

            for (;;) {
                Future<T> f = ecs.poll();
                if (f == null) {
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    else if (active == 0)
                        break;
                    else if (timed) {
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    else
                        f = ecs.take();
                }
                if (f != null) {
                    --active;
                    try {
                        return f.get();
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);
        }
    }

    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }

    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                           long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks) {
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                execute(f);
            }
            for (int i = 0, size = futures.size(); i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    try {
                        f.get();
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));

            final long deadline = System.nanoTime() + nanos;
            final int size = futures.size();

            // Interleave time checks and calls to execute in case
            // executor doesn't have any/much parallelism.
            for (int i = 0; i < size; i++) {
                execute((Runnable)futures.get(i));
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L)
                    return futures;
            }

            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    if (nanos <= 0L)
                        return futures;
                    try {
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    nanos = deadline - System.nanoTime();
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

}

5、ThreadPoolExecutor类

源码太多这里不再全部粘贴,有兴趣的可以自己研究~~我们主要讲一下使用该类创建线程池时的一些参数和几个构造方法。

核心参数如下:

参数名称解释
corePoolSize核心线程数。
maxmunPoolSize最大线程数。当核心线程全部被利用,工作队列任务已满,corePoolSize < maxmunPoolSIze 时才会创建新的线程。
keepAliveTime非核心线程活跃时间。超过该时间,线程被销毁。
unit非核心线程活跃时间单位。
workQueue工作队列,也叫阻塞队列。ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue。
threadFactory线程创建时使用的工厂。
handler拒绝策略。线程池对拒绝任务的处理策略。AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy。

5.1、workQueue工作队列(也叫阻塞队列)类型

任务流程:
任务在刚开始提交时,会直接交给核心线程执行。核心线程都在执行任务之后,任务会被保留在工作队列中。当任务越来越多,工作队列满了之后(且corePoolSize < maxmunPoolSize时),会创建新的线程来执行工作队列中的任务。

工作队列名称介绍
有界工作队列ArrayBlockingQueue有界缓存队列。必须指定大小。
无界工作队列LinkedBlockingQueue无界缓存队列。可指定队列大小,不指定则为无界队列。
同步队列SynchronousQueue直接将任务直接提交给线程,不保持

注:LinkedBlockingQueue在使用时,如果不指定size(即无界),会导致工作队列无法堆满,而线程数无法达到maxmunPoolSize

5.2、handler拒绝策略类型

这里不再详细介绍,后面在写相关详文。

拒绝策略介绍
AbortPolicy丢弃任务并抛出RejectedExecutionException异常
DiscardPolicy丢弃掉提交的任务,但不抛出异常
DiscardOldestPolicy如果任务添加到线程池中被拒绝,线程池丢弃等待队列中最旧的任务,然后将被拒绝的任务添加到等待队列中。
CallerRunsPolicy如果任务被拒绝,由提交该任务的线程处理当前任务

5.3、ThreadPoolExecutor构造方法创建线程池

ThreadPoolExecutor 类一共提供了四种构造方式,来创建线程池,但都大同小异。

初始化数据

    private static List<User> userList = new ArrayList<>();

    //初始化任务数据 userList
    private static void init(){

        User zhangSan = new User(1,"zhangSan",21);
        User liSi = new User(2,"liSi",22);
        User wangWu = new User(3,"wangWu",23);
        User zhaoLiu = new User(4,"zhaoLiu",24);

        userList.add(zhangSan);
        userList.add(liSi);
        userList.add(wangWu);
        userList.add(zhaoLiu);
    }

1、方式一

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        
        //调用参数最全的重载方法                      
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

其中 defaultHandler 为默认的拒绝策略AbortPolicy

    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

代码用例

    @Test
    void testCreateMethod1(){
        CreateThreadPoolTest.init();

        //创建线程池
        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(1,2,120L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(2));

        //任务list
        List<Future> futures = new ArrayList<>();

        //遍历任务list
        for (User user : userList) {

            //将每一个user提交给线程池

            //submit的入参对象 可以为实现的Runnable对象,也可以为Callable对象,上面我们提到过,这里采用Callable
            Future<Object> submit = executor.submit(new Callable<Object>() {
                @Override
                public String call() throws Exception {

                    //调用实际执行的业务,建议将每个任务需要处理的业务封装成方法调用并try,try的目的是为了不影响其他任务执行
                    try {

                        //打印用户名称
                        printCurrentThreadName(user);

                    } catch (Exception e) {
                        //打印错误日志
                        //....
                    }
                    //返回任务执行的结果
                    return "执行成功";
                }
            });

            //添加到任务队列
            futures.add(submit);
        }

        //执行任务
        for (Future future : futures) {
            try{
                //get方法要求try或者直接抛出异常
                future.get();
            }catch (Exception e){
                //打印错误日志
                //....
            }
        }
    }

    /**
     * 打印当前用户名称,以及处理当前用户的线程
     */
    private void printCurrentThreadName(User user){
        System.out.println("当前线程 ----> " + Thread.currentThread().getName()+", 执行用户 ---->" + user.getUserName());
    }

执行结果

当前线程 ----> pool-1-thread-1, 执行用户 ---->zhangSan
当前线程 ----> pool-1-thread-2, 执行用户 ---->zhaoLiu
当前线程 ----> pool-1-thread-1, 执行用户 ---->liSi
当前线程 ----> pool-1-thread-1, 执行用户 ---->wangWu

Process finished with exit code 0

2、方式二

自定义线程池工厂

 ThreadPoolExecutor executor
                = new ThreadPoolExecutor(1,2,120L,TimeUnit.SECONDS,new LinkedBlockingQueue(2), Executors.defaultThreadFactory());
   @Test
    void testCreateMethod1(){
        CreateThreadPoolTest.init();

        //创建线程池
        ThreadPoolExecutor executor
                = new ThreadPoolExecutor(1,2,120L,TimeUnit.SECONDS,new LinkedBlockingQueue(2), Executors.defaultThreadFactory());

        //任务list
        List<Future> futures = new ArrayList<>();

        //遍历任务list
        for (User user : userList) {

            //将每一个user提交给线程池

            //通过lambda表达式
            Future submit = executor.submit(() -> {
                try {

                    printCurrentThreadName(user);

                } catch (Exception e) {

                }
            });

            //添加到任务队列
            futures.add(submit);
        }

        //执行任务
        for (Future future : futures) {
            try{
                //get方法要求try或者直接抛出异常
                future.get();
            }catch (Exception e){

            }
        }
        //关闭线程池
        executor.shutdown();
        try{
            executor .awaitTermination(10L, TimeUnit.MINUTES);
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }
    }

3、方式三

自定义拒绝策略

 ThreadPoolExecutor executor
                = new ThreadPoolExecutor(1,2,120L,TimeUnit.SECONDS,new LinkedBlockingQueue(2), new ThreadPoolExecutor.AbortPolicy());
    @Test
    void testCreateMethod1(){
        CreateThreadPoolTest.init();

        //创建线程池
        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(1,2,120L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(2), new ThreadPoolExecutor.AbortPolicy());

        //任务list
        List<Future> futures = new ArrayList<>();

        //遍历任务list
        for (User user : userList) {

            //将每一个user提交给线程池

            //通过Runnable匿名内部类
            Future submit = executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {

                        printCurrentThreadName(user);

                    } catch (Exception e) {

                    }
                }
            });

            //添加到任务队列
            futures.add(submit);
        }

        //执行任务
        for (Future future : futures) {
            try{
                //get方法要求try或者直接抛出异常
                future.get();
            }catch (Exception e){

            }
        }
        //关闭线程池
        threadPoolExecutor.shutdown();
        try{
            executor .awaitTermination(10L, TimeUnit.MINUTES);
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }
    }

4、方式四

参数最全的自定义重载方法

 ThreadPoolExecutor executor
                = new ThreadPoolExecutor(1,2,120L,TimeUnit.SECONDS,new LinkedBlockingQueue(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        

以上已介绍过通过Runnable和Callable方式提交,这里不再赘述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值