线程池

线程池

线程池_第1张图片

为什么要使用线程池?
线程是处理器调度的基本单位。我们会为每一个请求都独立创建一个线程,而操作系统创建线程、切换线程状态、结束线程都要使用CPU进行调度。使用线程池能够更好对线程进行管理、复用等。

JDK为我们提供了那些支持?
ScheduledThreadPoolExecutor
ThreadPoolExecutor(最核心)
ForkJoin Pool

ThreadPoolExecutor的结构
线程池_第2张图片
核心属性:
corePoolSize #核心线程数
maxinmumPoolSize #线程总数 非核心数=总数-核心数
keepAliveTime #当前线程数大于核心线程数时 非核心线程的等待被执行的等待时间
TimeUnit unit #时间单位
workQueue #保存未被执行的任务队列
RejectedExecutionHandler #拒绝处理器

poolExecutor 线程池对象
submit(Callable x) execute(Runnable x) 将任务送入到任务队列
Runnable接口没有返回值,Callable有返回值
核心:
当前运行线程数 小于corePoolSize 任务直接交给核心线程进行执行(通过线程调度执行任务)
当前运行线程数 大于或等于 corePoolSize 任务且满足队列规则 任务将进入任务队列进行等待
当前运行线程数 大于或等于 corePoolSize 任务且不满足队列规则 任务进入非核心线程(这类线程有存活时间,不一定会执行成功)

任务队列(实现BlockingQueue接口)
SyschronousQueue:每一次add()插入 必须要等待相对删除/读取操作
ArrayBlockingQueue:数组的方式,大小创建后不能改变大小,具有阻塞特性。
LinkedBlockingQueue:无限容量 基于链表的形式
LinkedBlockingDeque :无限双端链表队列,可以从两头进行元素的读/取操作
PriorityBlockingQueue:按照优先级进行内部元素排序的无限队列。
LinkedTransferQueue:无限队列,先进先出,具有阻塞特性。
#阻塞特性:当队列满了,便会阻塞等待,直到有元素出队,后续的元素才可以被加入队列。

拒绝处理器
适用:那些既不能进入核心线程、等待队列,也无法创建新的线程执行(即非核心线程),或者线程异常等。
CallerRunsPolicy:直接运行该任务的run方法,但不是在线程池内部
AbortPolicy:RejectedExecutionException异常抛出(默认)
DiscardPolicy:不会做任何处理
DiscardOldestPolicy:检查等待队列 强行取出队列头部任务 进行执行

ForkJoin框架

线程池_第3张图片
ForkJoin采用“工作窃取模式”,当有新的任务它可以将其拆分成更小的任务去执行,之后将结果进行合并,得到最终的结果。这种思想,类似于map/reduce的分而治之的思想处理任务。

ForJoin的简单实现

ForkJoinPool forkJoinPool = new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
ForkJoinTask task = new ForkJoinWork(0L,10000000000L);//参数为起始值与结束值
Long invoke = forkJoinPool.invoke(task);#执行ForkJoin任务中的compute()

ForJoinTask必须继承RecursiveTask(有返回值)或者 RecursiveAction (没有返回值)

public class ForkJoinWork extends RecursiveTask {
    private Long start;//起始值
    private Long end;//结束值
    public static final  Long critical = 100000L;//临界值
    public ForkJoinWork(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

@Override
protected Long compute() {
    //判断是否是拆分完毕
    Long lenth = end - start;
    if(lenth<=critical){
        //如果拆分完毕就相加
        Long sum = 0L;
        for (Long i = start;i<=end;i++){
            sum += i;
        }
        return sum;
    }else {
        //没有拆分完毕就开始拆分
        Long middle = (end + start)/2;//计算的两个值的中间值
        ForkJoinWork right = new ForkJoinWork(start,middle);
        right.fork();//拆分,并压入线程队列
        ForkJoinWork left = new ForkJoinWork(middle+1,end);
        left.fork();//拆分,并压入线程队列

        //合并
        return right.join() + left.join();
    }
}
}

你可能感兴趣的:(线程池)