J.U.C体系进阶(一):juc-executors 执行器框架
Java - J.U.C体系进阶
作者:Kerwin
邮箱:806857264@qq.com
说到做到,就是我的忍道!
主要内容:
- juc-executors 执行器框架
- juc-locks 锁框架
- juc-atomic 原子类框架
- juc-sync 同步器框架
- juc-collections 集合框架
总览:
juc-executors 执行器框架
Executors框架基本概述
ScheduledExecutorService
// ScheduledExecutorService其实属于上层代码,和下面三种的实现不一致
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("run "+ System.currentTimeMillis());
}
}, 0, 1000, TimeUnit.MILLISECONDS);
}
newSingleThreadScheduledExecutor 一次只有一个线程,每隔一秒钟执行一次
newScheduledThreadPool(5); 延时线程池,允许池内五个线程运行
schedule - 出问题后,依然按顺序执行
scheduleAtFixedRate - 出问题后,立即加速执行,按原定计划执行
// Testin线程池做法
1.随着项目启动,创建周期性执行线程池ScheduledExecutorService --- 确定其核心线程工作数量
2.随着项目启动,初始化查询线程-内含任务队列及再初始化工作线程池
3.查询线程中run方法复杂查询需要处理的任务,然后放到队列中,初始化工作线程(传递任务及队列),由当前工作线程池去管理执行
4.工作线程处理,处理完毕后,移除当前队列中对应的一条信息
注:这里说的队列用的是比较low比的map...
newFixedThreadPool
/**
* Executors默认方法 - 创建一个具有固定线程数的Executor,控制最大线程并发数
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
// 阿里推荐的创建方式:
ThreadFactory nameFactory = new ThreadFactoryBuilder().setNameFormat("fixThread").build();
ExecutorService eService = new ThreadPoolExecutor(
5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
nameFactory, new ThreadPoolExecutor.AbortPolicy());
// 参数说明:
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
nameFactory: 线程命名,让名字更有意义
handler: 线程池对拒绝任务的处理策略
newSingleThreadExecutor
最大运行线程数为 1
简单创建方式:
ExecutorService service = Executors.newSingleThreadExecutor();
// 阿里推荐的创建方式:
ThreadFactory nameFactory = new ThreadFactoryBuilder().setNameFormat("single").build();
ExecutorService eService = new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
nameFactory, new ThreadPoolExecutor.AbortPolicy());
newCachedThreadPool
// 可缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
// 阿里推荐的创建方式:
ThreadFactory nameFactory = new ThreadFactoryBuilder().setNameFormat("single").build();
ExecutorService eService = new ThreadPoolExecutor(
0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
nameFactory, new ThreadPoolExecutor.AbortPolicy());
普通线程池 - ThreadPoolExecutor
/**
* 使用给定的参数创建ThreadPoolExecutor.
*
* @param corePoolSize 核心线程池中的最大线程数
* @param maximumPoolSize 总线程池中的最大线程数
* @param keepAliveTime 空闲线程的存活时间
* @param unit keepAliveTime的单位
* @param workQueue 任务队列, 保存已经提交但尚未被执行的线程
* @param threadFactory 线程工厂(用于指定如果创建一个线程)
* @param 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;
}
拒绝策略:
1.AbortPolicy(默认)
AbortPolicy策略其实就是抛出一个RejectedExecutionException异常:
2.DiscardPolicy
DiscardPolicy策略其实就是无为而治,什么都不做,等任务自己被回收:
3.DiscardOldestPolicy
DiscardOldestPolicy策略是丢弃任务队列中的最近一个任务,并执行当前任务:
4.CallerRunsPolicy
CallerRunsPolicy策略相当于以自身线程来执行任务,这样可以减缓新任务提交的速度。
线程池工作详解:
关于ThreadPoolExecutor这个线程池,最重要的是根据系统实际情况,合理进行线程池参数的设置以及阻塞队列的选择。现实情况下,一般会自己通过ThreadPoolExecutor的构造器去构建线程池,而非直接使用Executors工厂创建,因为这样更利于对参数的控制和调优。
另外,根据任务的特点,要有选择的配置核心线程池的大小:
- 如果任务是 CPU 密集型(需要进行大量计算、处理),则应该配置尽量少的线程,比如 CPU 个数 + 1,这样可以避免出现每个线程都需要使用很长时间但是有太多线程争抢资源的情况;
- 如果任务是 IO密集型(主要时间都在 I/O,CPU 空闲时间比较多),则应该配置多一些线程,比如 CPU 数的两倍,这样可以更高地压榨 CPU
Future模式
// J.U.C -> 提供异步执行结果支持
// call接口提供执行返回结果,需要注意的是:
// isDone 表示是否执行完毕
// get 如果线程未执行完毕,则会阻塞当前线程
public static void main(String[] args) throws Exception {
FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("我是线程 i am working");
Thread.sleep(3000);
return "hello futureTask";
}
});
new Thread(future).start();
System.out.println("是否完成: " + future.isDone());
System.out.println("阻塞等待结果: " + future.get());
}
Fork/Join - 工作窃取算法(work-stealing)
// Fork/Join框架是Java7提供的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。使用工作窃取(work-stealing)算法,主要用于实现“分而治之”。
// 应用场景非常明确,可以在大任务线程下再进行分割,当然这是对于Executtor的补充,所以总是有别的线程池通过代码的方式去替代它,但这个思想应该理解和掌握
/***
* Fork/Join 工作窃取算法算法
*
* @author 柯贤铭
* @date 2019年4月19日
* @email 806857264@qq.com
*/
public class TestFork {
public static void main(String[] args) {
// 模拟数组
int[] intArr = new int[10000];
for (int i = 0; i < 10000;i++) {
intArr[i] = i;
}
// ForkJoinPool
ForkJoinPool executor = new ForkJoinPool();
ArraySumTask task = new ArraySumTask(intArr, 0, 9999);
ForkJoinTask<Long> future = executor.submit(task);
// ForkJoinTask在执行的时候可能会抛出异常,但是没办法在主线程里直接捕获异常,所以主动捕获
if (future.isCompletedAbnormally()) {
System.out.println(future.getException());
}
try {
Long start = System.currentTimeMillis();
System.out.println("result: " + future.get());
System.out.println("耗时: " + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class ArraySumTask extends RecursiveTask<Long> {
private int[] array;
private int begin;
private int end;
private static final int THRESHOLD = 100;
public ArraySumTask(int[] array, int begin, int end) {
this.array = array;
this.begin = begin;
this.end = end;
}
@Override
protected Long compute() {
Long total = 0L;
// 分治算法
if (this.end - this.begin + 1 < ArraySumTask.THRESHOLD) {
for (int i = begin; i <= end; i++) {
total += array[i];
}
} else {
int middle = (this.begin + this.end) / 2;
ArraySumTask subtask1 = new ArraySumTask(this.array, begin, middle);
ArraySumTask subtask2 = new ArraySumTask(this.array, middle + 1, end);
// 执行子线程
invokeAll(subtask1, subtask2);
long sum1 = subtask1.join();
long sum2 = subtask2.join();
total = sum1 + sum2;
}
return total;
}
}
调度逻辑:
Fork/Join的内容博大精深,这只是非常的片面介绍了Fork框架的基础用法,如果刚好有实际需求,需要再仔细研读
J.U.C体系进阶(一):juc-executors 执行器框架的更多相关文章
- J.U.C体系进阶(二):juc-locks 锁框架
Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-locks 锁框架 接口说明 Lock接口 类型 名称 void loc ...
- J.U.C体系进阶(五):juc-collections 集合框架
Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-collections 集合框架 ConcurrentHashMap C ...
- J.U.C体系进阶(四):juc-sync 同步器框架
Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-sync 同步器框架 同步器名称 作用 CountDownLatch 倒 ...
- J.U.C体系进阶(三)- juc-atomic 原子类框架
Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-atomic 原子类框架 AtomicInteger AtomicInt ...
- 【JUC】JUC线程池框架综述
一.前言 在分析完了JUC的锁和集合框架后,下面进入JUC线程池框架的分析,下面给出JUC线程池的总体框架,之后再逐一进行分析. 二.JUC线程池框架图 说明:从上图可知,JUC线程池框架中的其他接口 ...
- Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)
上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...
- JUC锁之 框架
根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和"JUC包中的锁". 同步锁 即通过synchronized关键字来进行同步,实现对竞争资源 ...
- java并发编程(十九)----(JUC集合)总体框架介绍
本节我们将继续学习JUC包中的集合类,我们知道jdk中本身自带了一套非线程安全的集合类,我们先温习一下java集合包里面的集合类,然后系统的看一下JUC包里面的集合类到底有什么不同. java集合类 ...
- Android 进阶Android 中的 IOC 框架 【ViewInject】 (上)
1.概述 首先我们来吹吹牛,什么叫IoC,控制反转(Inversion of Control,英文缩写为IoC),什么意思呢? 就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量, ...
随机推荐
- 怎样在LaTeX中使用中文
因为疫情在家中上课,作业提交都必须使用PDF.反正时间充裕,不如趁机回顾一下LaTeX的使用. 之前一直用的是Vimtex,但是感觉还是不太方便,于是改用了Texpad.Texpad的强大之处在于它支 ...
- VS Code WebApi系列——3、发布
上两篇已经实现了WebApi及基于jwt的Token设置,那么功能做完了,该发布WebApi了.为什么要对发布进行一下说明呢,因为是基于vscode和.netcore的发布,所以可能会遇到莫名奇妙的问 ...
- springboot 集成mybatis时日志输出
application.properties(yml)中配置的两种方式: 这两种方式的效果是一样的,但是下面一种可以指定某个包下的SQL打印出来,上面这个会全部的都会打印出来.
- Python 简明教程 --- 13,Python 集合
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 如果代码和注释不一致,那很可能两者都错了. -- Norm Schryer 目录 前几节我们已经介绍 ...
- 千金良方说:"我现在奉上179341字的MySQL资料包,还来得及吗?有"代码段、附录、和高清图!!"
上一篇"上发布过"一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了",我在更早之前,在微信公众号"老叶茶馆"上发布 ...
- sublime清空控制台
解决方法 – 只需运行print('\n'*100)打印100个换行符,您将无法看到任何以前的输出,除非你向上滚动一些距离.
- redis.cluster/memcached.cluster/wmware esxi
1. 安装配置redis的cluster 集群 redis 集群高可用 实验环境 192.168.198.131 openvpn-server #42-Ubuntu SMP Mon Jun 8 14: ...
- MySQL函数索引及优化
很多开发人员在使用MySQL时经常会在部分列上进行函数计算等,导致无法走索引,在数据量大的时候,查询效率低下.针对此种情况本文从MySQL5.7 及MySQL8.0中分别进行不同方式的优化. 1. M ...
- .NET 开源项目 StreamJsonRpc 介绍
StreamJsonRpc 是一个实现了 JSON-RPC 通信协议的开源 .NET 库,在介绍 StreamJsonRpc 之前,我们先来了解一下 JSON-RPC. JSON-RPC 介绍 JSO ...
- 探讨NET Core数据进行3DES加密或解密弱密钥问题
前言 之前写过一篇<探讨.NET Core数据进行3DES加密和解密问题>,最近看到有人提出弱密钥问题,换个强密钥不就完了吗,猜测可能是与第三方对接导致很无奈不能更换密钥,所以产生本文解决 ...