Java线程池源码解析

本文详细解析了Java线程池的继承关系,包括ExecutorService、ThreadPoolExecutor等接口和类的实现。文章通过源码分析了线程池的核心方法execute的实现逻辑,介绍了如何添加任务到任务阻塞队列以及非核心线程的处理。此外,还展示了线程池的工作模型图,并探讨了线程池的四种拒绝策略:CallerRunsPolicy、AbortPolicy、DiscardPolicy和DiscardOldestPolicy,以及自定义拒绝策略的可能性。
摘要由CSDN通过智能技术生成

1. 线程池的继承关系

从上图可以看出来最顶层的接口为 Executor ,下面看一下这个接口中的方法

public interface Executor {
    //只有一个方法execute
    void execute(Runnable command);
}

从代码中可以看出来只有一个 execute 方法。这也是我常用的一个来运行 Runable 的一种方式。然后看一下继承了 Executor 接口的 ExecutorService 接口中有哪些我们熟悉的而常用的方法

public interface ExecutorService extends Executor {
    
    // 关闭线程池,已提交的任务继续执行,不接受继续提交新任务
    //写例子的时候用到(PS在实际的项目组基本上没有用到,反正我是没有)
    void shutdown();
    
    //关闭线程池,尝试停止正在执行的所有任务,不接受继续提交新任务
     //这个也是基本上没用到
    List<Runnable> shutdownNow();
​
    // 线程池是否已关闭
    // 还是没有用到
    boolean isShutdown();
​
    // 这个方法必须在调用shutdown或shutdownNow方法之后调用才会返回true
    //尴尬没用过
    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);
​
    //带返回值---(成功返回值为null 有兴趣的可以去尝试一下,源码的英文注释上面有说明)
    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;
}

演示代码:

public class InvokeAllTest {
​
    public static void main(String[] args) throws  Exception{
        ExecutorService service = Executors.newFixedThreadPool(10);
        Collection<Test> a = new ArrayList<>();
        for(int i = 0; i < 10; ++i){
            a.add(new Test());
        }
        //System.out.println( service.invokeAny(a));
        System.out.println( service.invokeAll(a));
    }
​
}
​
class Test implements Callable<String>{
​
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    @Override
    public String call() throws Exception {
​
        TimeUnit.SECONDS.sleep((int)(Math.random()*10));
​
        return Thread.currentThread().getName();
    }
}

看一下最后一个接口 ScheduledExecutorService 计划执行接口,从命名上就不难看出来这个用于执行任务的。

public interface ScheduledExecutorService extends ExecutorService {
​
    /**
     * 创建并执行在给定延迟之后启用的一次性操作。
     */
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
​
    /**
     * 创建并执行在给定延迟之后启用的一次性操作。返回ScheduledFuture<V>
     */
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);
​
    /**
     * 按指定频率周期执行某个任务。
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
​
    /**
     * 按指定频率间隔执行某个任务。
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);
​
}

另外,由于线程池支持获取线程执行的结果,所以,引入了 Future 接口,RunnableFuture 继承自此接口,然后我们最需要关心的就是它的实现类 FutureTask。到这里,记住这个概念,在线程池的使用过程中,我们是往线程池提交任务(task),使用过线程池的都知道,我们提交的每个任务是实现了 Runnable 接口的,其实就是先将 Runnable 的任务包装成 FutureTask,然后再提交到线程池。这样,读者才能比较容易记住 FutureTask 这个类名:它首先是一个任务(Task),然后具有 Future 接口的语义,即可以在将来(Future)得到执行的结果。

2. AbstractExecutorService

接着来看一下在抽象类 AbstractExecutorService 实现了哪些方法

public abstract class AbstractExecutorService implements ExecutorService {
​
    /**
     * Runnable 转换为 Callable 的方法带指定返回值
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
​
    /**
     * Runnable 转换为 Callable 的方法,不带指定返回值
     */
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
​
    /**
     * 
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        //这里看一看出来在Runnable submit方法返回值为Future get的值为null
        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();
         //这里看一看出来在Runnable submit方法返回值为Future get的值为result
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
​
    /**
     * Callable类型
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
​
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾听铃的声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值