Kamafeel

求其上,得其中;求其中,得其下,求其下,必败


  • 首页

  • 归档

parallelStream

发表于 2020-09-14 | 更新于 2022-02-28 | 分类于 JAVA , 并发

parallelStream内部逻辑

底层由ForkJoinPool.commonPool 线程池创建的线程进行运行。

并行流内部使用了默认的ForkJoinPool(7.2节会进一步讲到分支/合并框架),它默认的线程数量就是你的处理器数量,这个值是由Runtime.getRuntime().available- Processors()得到的。 但是你可以通过系统属性java.util.concurrent.ForkJoinPool.common. parallelism来改变线程池大小,如下所示: System.setProperty(“java.util.concurrent.ForkJoinPool.common.parallelism”,”12”); 这是一个全局设置,因此它将影响代码中所有的并行流。反过来说,目前还无法专为某个 并行流指定这个值。一般而言,让ForkJoinPool的大小等于处理器数量是个不错的默认值, 除非你有很好的理由,否则我们强烈建议你不要修改它。

// 设置全局并行流并发线程数
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "12");
System.out.println(ForkJoinPool.getCommonPoolParallelism());// 输出 12
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
System.out.println(ForkJoinPool.getCommonPoolParallelism());// 输出 12

与Fork-Join线程池关系

反面案例

1.多个parallelStream之间默认使用的是同一个线程池,所以IO操作尽量不要放进parallelStream中,否则会阻塞其他parallelStream
使用并行流的时候是无法保证元素的顺序的

2.本身线程数有限,不要用于应对高并发接口

参考

https://cloud.tencent.com/developer/article/1544929

FactoryBean

发表于 2020-09-14 | 分类于 Spring , 源码解读

FactoryBean

  • 实列化bean存在复杂性,通过配置方式不够灵活,Spring提供此类通过编程方式提供灵活性。
  • FactoryBean的特殊之处在于它可以向容器中注册两个Bean,一个是它本身,一个是FactoryBean.getObject()方法返回值所代表的Bean
  • 使用FactoryBean是封装复杂的构造逻辑或使在Spring中更容易配置高度可配置对象的一种好习惯

Spring提供一个简单模板代码
AbstractFactoryBean

应用案例:

  • https://juejin.im/post/6844903954615107597#heading-2
  • https://www.cnblogs.com/aspirant/p/9082858.html
  • https://www.baeldung.com/spring-factorybean

数据结构-堆

发表于 2020-09-12 | 更新于 2021-11-18 | 分类于 数据结构

数据结构-散列表

发表于 2020-09-12 | 更新于 2022-02-28 | 分类于 数据结构

日常注意

hashMap的扩容存在大量rehash,注意如果知道需存放容量,一次性设置初始容量。
避免16的反复扩容

加载因子0.75属于泊松分布,没特殊必要不要骚改。

乘积值

public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

获取hashCode 31作为乘积值,原因是减少Hash碰撞概率

扰动函数

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

(h = key.hashCode()) ^ (h >>> 16)。把哈希值右移16位,也就正好是自己长度的一半,之后与原哈希值做异或运算,这样就混合了原哈希值中的高位和低位,增大了随机性

初始化容量和负载因子

散列数组需要一个2的倍数的长度,因为只有2的倍数在减1的时候,才会出现01111这样的值

static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }

如果传入奇数的初始容量,最终会转换为最临近的2的倍数的二进制

扩容元素

原哈希值与扩容新增出来的长度16,进行&运算,如果值等于0,则下标位置不变。如果不为0,那么新的位置则是原来位置上加16

题外话

特别注意HashMap Key存放对象,需要重写hashcode和equal方法
JAVA8之后,HashMap的Value链表容量超过8,是改为红黑树,减少查询的时间复杂度O(logn)

类别 key value为null
hashMap 支持
ConcurrentSkipListMap 不支持
ConcurrentHashMap 不支持
HashTable 不支持
linkedhashMap 支持
treeMap key不支持,value支持

为null存在二义性,无法边变是找不到,还是缺失value为null

Collections.synchronizedMap勉强实现同步,key value又可以为null

参考

https://www.jianshu.com/p/ecdf00e33b98
https://www.cnblogs.com/xinzhao/p/5644175.html
https://cloud.tencent.com/developer/article/1690271

数据结构-队列

发表于 2020-09-12 | 更新于 2021-11-18 | 分类于 数据结构

alt

类型 实现 描述
Queue LinkedBlockingQueue 由链表结构组成的有界阻塞队列
Queue ArrayBlockingQueue 由数组结构组成的有界阻塞队列
Queue PriorityBlockingQueue 支持优先级排序的无界阻塞队列
Queue SynchronousQueue 不存储元素的阻塞队列
Queue LinkedTransferQueue 由链表结构组成的无界阻塞队列
Deque LinkedBlockingDeque 由链表结构组成的双向阻塞队列
Deque ConcurrentLinkedDeque 由链表结构组成的线程安全的双向阻塞队列 CAS

数据结构-链表

发表于 2020-09-12 | 更新于 2022-02-28 | 分类于 数据结构

CopyOnWriteArrayList 多线程安全实现机制和弊端

CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

当有新元素加入的时候,如下图,创建新数组,并往新数组中加入一个新元素,这个时候,array这个引用仍然是指向原数组的。

alt

ArrayList

contains 参数为对象,注意是否需要重写equals

数据结构-数组

发表于 2020-09-12 | 更新于 2021-11-18 | 分类于 数据结构

案例

ArrayList 基于数组实现,涉及到动态扩容,数组拷贝。

插入数据

  • 尾部插入 时间复杂度 O(1),数组扩容

  • 中部/头部插入,查找是O(1),插入存在数组拷贝

ArrayList.set方法会先判断数组真实数据size长度,而非数组构造方法长度。

btw:数组分配的内存空间是连续地址段,由于CPU二级缓存的存在,ArrayList的性能,多数情况下超过linkedList(双向链表实现,非数组)

如果不需要首位的频繁插入,基本不考虑使用LinkedList

数据结构-树

发表于 2020-09-11 | 更新于 2021-11-18 | 分类于 数据结构

1.二叉搜索树

容易倾斜;导致性能和链表类似。

2.红黑树

(最大好处,查找时间复杂度,是logn)

数学理论支撑 左旋,右旋 – 目的是红黑树,尽量平衡。 一个节点下面的2个节点的差,不会大于较小的那个节点的2倍差异。

新插入的节点都是RED,存在规则和情况,负责进行左旋或者右旋,改色。

3 2-3树

二三树允许在一个节点中可以有两个元素,等元素数量等于3个时候再进行调整
alt

LSM-Tree

LSM-Tree全称是Log Structured Merge Tree,是一种分层,有序,面向磁盘的数据结构,其核心思想是充分了利用了,磁盘批量的顺序写要远比随机写性能高出很多

alt

Hbase,Cassandra,Leveldb,RocksDB,MongoDB,TiDB,Kafka,ES均使用数据结构

B+Tree VS LSM-Tree
传统关系型数据采用的底层数据结构是B+树,那么同样是面向磁盘存储的数据结构LSM-Tree相比B+树有什么异同之处呢?

LSM-Tree的设计思路是,将数据拆分为几百M大小的Segments,并是顺序写入。

B+Tree则是将数据拆分为固定大小的Block或Page, 一般是4KB大小,和磁盘一个扇区的大小对应,Page是读写的最小单位。

在数据的更新和删除方面,B+Tree可以做到原地更新和删除,这种方式对数据库事务支持更加友好,因为一个key只会出现一个Page页里面,但由于LSM-Tree只能追加写,并且在L0层key的rang会重叠,所以对事务支持较弱,只能在Segment Compaction的时候进行真正地更新和删除。

因此LSM-Tree的优点是支持高吞吐的写(可认为是O(1)),这个特点在分布式系统上更为看重,当然针对读取普通的LSM-Tree结构,读取是O(N)的复杂度,在使用索引或者缓存优化后的也可以达到O(logN)的复杂度。

而B+tree的优点是支持高效的读(稳定的OlogN),但是在大规模的写请求下(复杂度O(LogN)),效率会变得比较低,因为随着insert的操作,为了维护B+树结构,节点会不断的分裂和合并。操作磁盘的随机读写概率会变大,故导致性能降低。

还有一点需要提到的是基于LSM-Tree分层存储能够做到写的高吞吐,带来的副作用是整个系统必须频繁的进行compaction,写入量越大,Compaction的过程越频繁。而compaction是一个compare & merge的过程,非常消耗CPU和存储IO,在高吞吐的写入情形下,大量的compaction操作占用大量系统资源,必然带来整个系统性能断崖式下跌,对应用系统产生巨大影响,当然我们可以禁用自动Major Compaction,在每天系统低峰期定期触发合并,来避免这个问题。

阿里为了优化这个问题,在X-DB引入了异构硬件设备FPGA来代替CPU完成compaction操作,使系统整体性能维持在高水位并避免抖动,是存储引擎得以服务业务苛刻要求的关键。

JVM Metaspace

发表于 2020-09-11 | 更新于 2022-02-28 | 分类于 JVM , 基础

Java 8 彻底将永久代 (PermGen) 移除出了 HotSpot JVM,将其原有的数据迁移至 Java Heap 或 Metaspace。这一篇文章我们来总结一下Metaspace(元空间)的特性。如有错误,敬请指出,谢谢~

引言:永久代为什么被移出HotSpot JVM了?
在 HotSpot JVM 中,永久代中用于存放类和方法的元数据以及常量池,比如Class和Method。每当一个类初次被加载的时候,它的元数据都会放到永久代中。

永久代是有大小限制的,因此如果加载的类太多,很有可能导致永久代内存溢出,即万恶的 java.lang.OutOfMemoryError: PermGen ,为此我们不得不对虚拟机做调优。

那么,Java 8 中 PermGen 为什么被移出 HotSpot JVM 了?我总结了两个主要原因(详见:JEP 122: Remove the Permanent Generation):

由于 PermGen 内存经常会溢出,引发恼人的 java.lang.OutOfMemoryError: PermGen,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM
移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。
根据上面的各种原因,PermGen 最终被移除,方法区移至 Metaspace,字符串常量移至 Java Heap。

探秘元空间
由于 Metaspace 的资料比较少,这里主要是依据Oracle官方的Java虚拟机规范及Oracle Blog里的几篇文章来总结的。

首先,Metaspace(元空间)是哪一块区域?官方的解释是:

In JDK 8, classes metadata is now stored in the native heap and this space is called Metaspace.

也就是说,JDK 8 开始把类的元数据放到本地堆内存(native heap)中,这一块区域就叫 Metaspace,中文名叫元空间。

阅读全文 »

mysql配置

发表于 2020-07-16 | 更新于 2021-11-18 | 分类于 数据库 , MYSQL

whereis mysql

which mysql

mysql –help|grep ‘my.cnf’

locate my.cnf

1…161718…21

Kamafeel

204 日志
57 分类
129 标签
© 2022 Kamafeel
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Pisces v7.1.2