您的位置:首页 > 其它

并发笔记(二)

2018-01-17 08:50 267 查看

并发容器

ConcurrentHashMap
:线程安全的HashMap,在高并发场景下比
Collections.synchronizedMap
性能好

CopyOnWriteArrayList
:读多写少的场合性能远好于Vector,写的时候加的重入锁,并且每次增加元素都会重新拷贝一个新数组替换老数组;读的时候不加锁;

ConcurrentLinkedQueue
:高效的并发队列使用链表实现

BlockingQueue
:阻塞队列接口,可作为数据共享通道

ConcurrentSkipListMap
:有序、安全、层级随机、空间换性能

锁优化

优化原则

减小锁持有时间,

减小锁粒度,尽量减小加锁的代码块

读写分离锁替换独占锁

锁分离,如(LinkedBlockingQueue put方法和take方法不同的锁)

锁粗化,频繁获取锁的时候,可考虑进行锁粗化

Java虚拟机对锁的优化

锁偏向:如果一个线程获得了锁,那么锁进入偏向模式,如果该线程再次请求锁时,无需做任何同步操作,
适合竞争不太激烈的场合,-XX:+UseBiasedLocking


轻量级锁:将对象头部作为指针,指向持有锁的线程堆栈内部来判断一个线程是否持有锁,如果线程获得轻量级锁则进入临界区;否则锁膨胀

自旋锁:锁膨胀后,为避免当前线程立即被挂起又获取锁之间的性能损耗,于是让当前线程做几个空循环(自旋),如果还能得到锁就进入临界区,否则挂起

锁消除:在进行编译时通过逃逸分析技术可实现锁消除(不需加锁的地方被认为错误加锁,虚拟机可以将此类的锁进行消除)

ThreadLocal

线程的局部变量,线程安全

使用ThreadLocalMap挂到Thread上存储数据,其初始容量为16,后续容量均以2的指数增长(其hash算法能保证容器大小为2的指数时均匀分布);

无锁

CAS (Compare And Swap):
cas(v, e, n)
原子操作,v标识要更新的变量,e表示预期值,n表示新值,仅当v=e时,才会将v设置为n,多个线程竞争时只有一个会成功;

基于CAS的原子操作类:
AtomicInteger AtomicLong ...


unsafe
: 封装了类似指针的操作,提供了类似CAS的原子性操作

AtomicStampedRefrence
可记录对象修改状态信息

无锁的数组:
AtomicIntegerArray  AtomicLongArrary


普通变量进行原子操作的支持:
AtomicIntegerFieldUpdater  AtomicReferenceFieldUpdater
,[1、变量必须可见 2、必须是volatile 3、不能使static变量]

SynchronousQueue


并行模式与算法

不变模式:对象一旦创建,其内部状态不再改变,如
String
以及基本类型包装类;不变模式通过规避问题的态度来处理多线程的访问控制

生产者与消费者:

普通实现:通过
BlockingQueue
来进行数据缓存以达到生产者和消费者解耦

无锁实现:利用
Disruptor
框架来实现,核心在于其使用环形队列(
RingBuffer
)来代替普通线性队列;生产者写入数据时、消费者消费数据时使用CAS操作确保数据安全。

Future模式:



并行搜索:如果有序则使用二分查找,否则将整体数组切分成若干段,然后单独线程基于小段进行搜索

并行排序:大多排序算法都是串行的,如果改为并行排序会增加算法复杂度

奇偶交换排序:将奇偶交换进行并行

并行希尔排序:根据希尔数值将分割成的小数组进行排序,然后重新计算希尔数值分割小数组,直到1为止;h>n的时候使用多线程;

NIO : 同步非阻塞

Channel
数据从channel读到buffer中,也可以将数据从buffer写到channel中

Buffer
用于与NIO通道的交互,一般分位4个步骤:

写入数据到buffer

调用
flip()
方法,从写模式切换到读模式

从buffer中读取数据

调用
clear()
或者
compact()
方法,清空缓存区等待再次写入

Selector
检测一到多个NIO通道,并能检测到通道是否为读写做好准备的组件;使用时,Channel应向Selector中进行注册(只接受非阻塞Channel)

AIO :异步非阻塞

不会加快IO,只在读完后进行通知

使用回调函数进行业务处理

参考资料《实战Java高并发程序设计》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息