如题,这篇文章主要讨论高性能编程的一些技巧,抓住高性能。
1.万丈高楼平地起,能起多高看基座。(一个高性能程序的基础就是从基础编码开始)
1.1 工具
没有哪个工具能独冠群雄,只有适合的。
java并发容器类:
ConcurrentHashMap:线程安全并发map,分segment的键值对容器,按hash算法查找,插入。理想状态,插入查找均是O(1)复杂度
CurrentListMap:跳表,并发容器,加索引的查找容器。
有数据元素按顺序排列,有多级索引,同一级别索引也按顺序排列。例如:查找k3,查找l2级索引找到k3>i1往右查找,找到i2即找到k3。
1.2 一个篱笆三个桩,一个好汉三个帮----多线程
1.2.1 原理
cpu运行速度远远高于内存读取,磁盘存取,为了充分利用cpu的高速度,当cpu执行的线程需要长时间io等待时,cpu就切换执行其他线程,本地保存执行位置,cpu空闲时可以再继续这个位置继续执行。
1.2.2 应用
利用现在机器多核cpu和每个cpu运行速度快的特性,将一个复杂耗时长的任务,拆分成多个可并行执行的小任务。
利用CountdownLatch,三个任务都执行完之后进行后续操作,初始设置C=3,每个线程完成后都会减一,到C=0时,继续往后执行。
类似的线程间通信工具还有CyclicBarrier:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活
Semaphore信号量:比如,每次下发3个通行证,那么来了5个线程,有三个可以执行,另外两个需要等待,直到有线程完成,保证同时执行的线程保持在一个阈值之内。
2.除了看自身,还要看环境。(jvm、系统)
2.1 内存:根据系统内存大小,实用用途等可以适当调整jvm堆内存、metaspace大小。
可通过参数-Xmx -Xms指定最大最小堆内存,一般设置物理内存一半即可,最大最小一致,以免扩容时带来性能损耗。
metaspace也叫对外内存,存放class元数据等,一般需要设置大小,以免内存不够。
2.2 垃圾收集器:一般情况下,实用默认收集器即可
serial:串行收集,一般只用作调试用,性能较低
Parallel scavenge(新生代)+Parallel Old(老年代):服务端默认收集器,性能比较出色
ParNew(新生代)+cms(老年代):采用标记清除算法,并发收集、低停顿、响应时间快,ParNew为并发版的serial。
g1:新生代,老年代均适用,新出的垃圾收集器,并发,并行,适用高吞吐量的应用
通过JVM参数 -XX:+UseG1GC 使用G1垃圾回收器
3.走出国门看世界。(网络也要高性能)
3.1 随着nio技术普及,可基本舍弃bio。
bio为传统的阻塞io,socket.accept()阻塞接受请求,降低线程利用率。
nio为非阻塞io,尝试接收请求,无论有无都立刻返回,如果有请求进来,将请求channel存放到list中,继续向下执行,遍历list,取出channel进行处理,然后进入新一轮循环,任何方法都不阻塞。这样一个线程就可以处理多个请求,大大提高线程利用率。
更进一步,可以将耗时操作放到其他线程中执行,利用现代计算机多核cpu优势。
3.2 reactor线程模型
3.3 利用netty等高性能网络框架。
3.3.1 利用reactor线程模型
3.3.2 自己封装的更强大的ByteBuf
可以视需要而定,将数据存放到直接内存中,可以申请pooledByteBuf缓存数据,可以内存复用,零拷贝机制等。
3.3.3 可扩展的责任链设计模式
不同的操作作为handler放入pipeline中,pipeline为channel内维护的责任链
通过pipeline.addlast(handler)动态增加需要处理的channel的功能。
handler分为入站和出站,不同的事件会触发不同类型的handler。