五、Java并发-线程池的底层实现

一、使用Java线程池的好处
(1)降低资源消耗。通过重复利用已创建的线程降低反复创建和销毁线程的消耗
(2)提高响应速度。任务不需要等线程创建就可以执行
(3)提高线程的可管理性。使用线程池可以统一分配,调优和监控

二、线程池对任务的处理流程
(1)线程池判断核心线程池中的线程是否有空余的。如果有,就创建新的工作线程完成任务,没有就下一步
(2)线程池判断工作队列是否满了。如果没满就存在工作队列中,满了就下一步
(3)线程池判断是否已经满了,没满就创建普通线程来执行,满了就交给饱和策略去处理
可以参照下面两幅图进行理解:
在这里插入图片描述在这里插入图片描述
具体的工作队列和饱和策略之后再进行讲解

三、Executor框架
框架图如下:
在这里插入图片描述
由此图可见,我们最基本的两大线程池类都是从Executor->ExecutorService->再继续往下实现,由此我们一步一步来:
(1)Executor接口
它是Executor框架的基础,是任务运行的简单接口,其中之定义了一个executor执行方法,不同的实现类,executor方法也就不一样

public interface Executor {
    void execute(Runnable command);
}

(2)ExecutorService接口
它扩展了Executor的接口,提供了一些管理执行器和任务的声明周期的方法

public interface ExecutorService extends Executor {
	void shutdown();
 	List<Runnable> shutdownNow();
	boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
           throws InterruptedException;
    <T> Future<T> submit(Callable<T> task);
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
           throws InterruptedException;
}

其中submit方法的参数可以是Callable的实例,跟其父接口的executor方法相比,可提供返回值(因为Callable有返回值)

(3)ScheduledExecutorService接口
其实现了ExecutorService接口,支持Future和定期执行任务

public interface ScheduledExecutorService extends ExecutorService {
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
    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);

}

(4) AbstractExecutorService实现类
对其父接口的方法进行了实现和重写,实现了一些逻辑
在这里插入图片描述
(5)ThreadPoolExecutor实现类(重点)
ThreadPoolExecutor通常使用工厂类Executors来实现(后文进行讲解)。
它的构造方法需要几个参数:
corePoolSize:核心线程数
maximumPoolSize:最大线程数(包括核心线程和一般线程)
BlockingQueue:暂时保存任务的工作队列
RejectedExecutionHandler:当线程池关闭或者饱和时,executor要调用的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.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;
    }

Executors可以创建3种类型的ThreadPoolExecutor:SingleThreadExecutor,FixedThreadPool,CachedThreadPool
下面分别了来介绍这3种线程池:
1)SingleThreadExecutor,创建单个线程的线程池,适用于保证循序的执行各个任务,并且在任意时间不会有多个线程是活动的。(只有一个核心线程)
2)FixedThreadPool,创建固定线程数的线程池,适用于限制线程数量的应用(只有核心线程)
3)CachedThreadPool,是创建大小无界的线程池,适用于执行很多短期任务的小程序。当需要线程并无缓存线程可用时,就创建新的线程;如果线程闲置的时间超过阈值则会被终止并移除缓存。(没有核心线程,都是临时线程,工作队列没有容量限制)

(6)ScheduledThreadPoolExecutor实现类(重点)
它实现了ScheduledExecutorService接口,并继承了ThreadPoolExecutor类,主要用来在给定的延迟之后运行任务,或者定期执行任务
有2种线程池:
1)SingleThreadScheduledExecutor:单个线程进行定时或者周期性的调度工作
2)ScheduledThreadPool:多个线程进行定时或者周期性的调度工作

(7)ForkJoinPool
这是JDK8才引入的线程池的创建方法,继承了AbstractExecutorService,实现了Fork/Join框架
可以创建1种线程池
1)WorkStealingPool内部会构建ForkJoinPool,利用working-stealing算法,并行的处理任务,不保证处理顺序

public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode) {
        this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
    }

四、什么是Fork/Join框架?
是一个把大任务分成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架,其中实现了work-stealing算法(下文讲)
在这里插入图片描述
(1)work-stealing算法
指某个线程从其他队列里窃取任务来执行,但是会尝试竞争,于是通常采用双端队列,被窃取任务线程永远从头部拿,窃取的从尾部拿。
任务流程图:
在这里插入图片描述
优点:充分利用线程进行并行运算,减少线程间竞争

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值