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 执行器框架的更多相关文章

  1. J.U.C体系进阶(二):juc-locks 锁框架

    Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-locks 锁框架 接口说明 Lock接口 类型 名称 void loc ...

  2. J.U.C体系进阶(五):juc-collections 集合框架

    Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-collections 集合框架 ConcurrentHashMap C ...

  3. J.U.C体系进阶(四):juc-sync 同步器框架

    Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-sync 同步器框架 同步器名称 作用 CountDownLatch 倒 ...

  4. J.U.C体系进阶(三)- juc-atomic 原子类框架

    Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! juc-atomic 原子类框架 AtomicInteger AtomicInt ...

  5. 【JUC】JUC线程池框架综述

    一.前言 在分析完了JUC的锁和集合框架后,下面进入JUC线程池框架的分析,下面给出JUC线程池的总体框架,之后再逐一进行分析. 二.JUC线程池框架图 说明:从上图可知,JUC线程池框架中的其他接口 ...

  6. Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)

    上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...

  7. JUC锁之 框架

    根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和"JUC包中的锁". 同步锁 即通过synchronized关键字来进行同步,实现对竞争资源 ...

  8. java并发编程(十九)----(JUC集合)总体框架介绍

    本节我们将继续学习JUC包中的集合类,我们知道jdk中本身自带了一套非线程安全的集合类,我们先温习一下java集合包里面的集合类,然后系统的看一下JUC包里面的集合类到底有什么不同. java集合类 ...

  9. Android 进阶Android 中的 IOC 框架 【ViewInject】 (上)

    1.概述 首先我们来吹吹牛,什么叫IoC,控制反转(Inversion of Control,英文缩写为IoC),什么意思呢? 就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量, ...

随机推荐

  1. 消息队列——ActiveMQ使用及原理浅析

    文章目录 引言 正文 一.ActiveMQ是如何产生的? 产生背景 JMS规范 基本概念 JMS体系结构 二.如何使用? 基本功能 消息传递 P2P pub/sub 持久订阅 消息传递的可靠性 事务型 ...

  2. 用VC++6.0,双击主对话框中的按钮时,不能跳转到代码处

    1. 首先在项目中--[生成]build--[清除解决方案]clean 2. 关闭项目 3. 删除项目中的[Debug]下所有文件 4. 把*.aps,*.clw,*.ncb,*.opt删掉----- ...

  3. Java学习笔记6(集合类)

    集合类 集合按照其存储结构可以分为两大类,即单列集合Collection和双列集合Map. Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,有List和Set两个重要子接口 ...

  4. python3.6 + django2.0.6 + xadmin0.6

    django2.0集成xadmin0.6报错集锦 http://www.lybbn.cn/data/bbsdatas.php?lybbs=50 1.django2.0把from django.core ...

  5. javaScript深入浅出之理解闭包

    javaScript深入浅出之理解闭包 引言 闭包是个老生长谈的话题了,对于闭包网上也有很多不同的看法 <你不知道的javaScript>对于闭包是这么定义的:函数创建和函数执行不在同一个 ...

  6. 为Promise添加finally方法支持,把小程序函数变成promise函数

    // 为Promise添加finally方法支持 Promise.prototype.finally = function (callback) {   let P = this.constructo ...

  7. PHP控制阿里云短信API接口实现短信群发功能

    阿里云短信支持先使用后支付的原则,价格为4分半1条. 通过SDK可以与网站功能的绑定,实现响应的短信发送功能 现已统一合并升级为:消息服务. 消息服务 阿里云消息服务(Message Service, ...

  8. 10、一个action中处理多个方法的调用第二种方法method的方式

    在实际的项目中,经常采用现在的第二种方式在struct.xml中采用清单文件的方式 我们首先来看action package com.bjpowernode.struts2; import com.o ...

  9. Mariadb之显式使用表锁和行级锁

    首先我们来看看mariadb的锁定概念,所谓锁就是当一个进程或事务在操作某一资源时,为了防止其他用户或者进程或事务对其进行资源操作,导致资源抢占而发生冲突,通常在A进程操作该资源时,会对该资源进行加锁 ...

  10. SpringBoot--数据库管理与迁移(LiquiBase)

    随着开发时间积累,一个项目会越来越大,同时表结构也越来越多,管理起来比较复杂,特别是当想要把一个答的项目拆分成多个小项目时,表结构拆分会耗很大的精力:如果使用LiquiBase对数据库进行管理,那么就 ...