ArrayList
是单线程,非线程安全,须要手动加锁实现同步lock或sychornized;由于代码不方便重用,CopyOnWriteArrayList
,它底层是:写加锁,ReentrantLock
,读不加锁;ReentrantLock
,基于AQS
同步,它的公平锁和非公平锁
,AQS
的基础又是CAS
。区别ReentrantLock和sychornized
,和jdk关键字优化有关。CopyOnWriteArrayList
底层数组由volatile
修饰,保证内存可见性
,这里涉及到重排序
,happen-before
,CAS
,内存屏障
。注意原子类型,底层就是volatile
修饰的。CAS
相似数据库中的乐观锁
。CopyOnWriteArrayList
的使用场景:读多写少的场景,避免大量临时数组产生
(由于每次写的时候,须要两个数组,写操做并发高,致使新生代产生大量临时数组,须要大量GC)、黑/白名单
(利用分布式Nginx实现ip黑名单,限流,负载均衡,反爬虫),同包下还有ConcurrentHashMap
,7与8的Hashmap和ConcurrentHashMap区别
。保证思路连续性java
ConcurrentModificationException并发修改异常
,产生于iterator迭代遍历ArrayList,删除一个元素,产生异常,for/foreach也是,expectedModCount
表示修改次数指望值,初始值与modCount
相等,可是修改集合成员时,modCount
会变化,当二者不相等是,抛出这个异常,因此须要移除时不能使用list.remove(xxx),而是使用iterator.remove(),由于这个方法会设置那两个参数相等。
说出在什么场景下出现异常
(发现问题能力)
、说出异常缘由(分析问题能力)
、说出解决方案(解决问题能力)
、对一个小问题的扩展和延伸(总结问题能力)
示例:发现问题——ArrayList遍历出现异常、分析问题——找到源码缘由、解决问题——使用迭代器remove方法能够避免、总结问题——多线程场景下迭代器remove方法产生问题引出并发容器
引出CopyOnWriteArrayList,在查看mysql驱动程序类的时候Driver中发现的
mysql
lock.lock(); //加锁,保证线程安全 Arrays.copyOf(); //拷贝出新数组 private volatile transient Object[] array; lock.unlock(); //finally中解锁,防止出现异常致使锁不释放 /** * 大体流程都是 先lock一下保证线程安全,拷贝出新数组,操做,修改原数组引用指向新数组,unlock解锁 * 高并发读请求,走的是旧数组。 */
延伸至 volatile关键字
volatile是保证线程内存可见性 ,区别于加锁。
volatile经过JVM底层一些指令,例如:happen-before规则,内存屏障等技术,保证cpu0放入到memory内存中,执行jvm中指令,强制硬件层面上,其余cpu的cache缓存为无效状态,强制从memory中获取新值,放到各自的缓存中进行计算。"大体是清其余cpu缓存,再从新拿缓存"
web
延伸至 CAS原子类型操做
CAS(Compare and Swap)
原子类型:保证操做都是线程安全的。
例如:AtomicInteger 底层有一个 private volatile int value; //实际就是int + volatile修饰面试
内存值V
、旧的预期值A
、要修改的新值B
当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作。
重入锁
:同一时间,只有一个线程可使用临界资源;公平锁
是如果同一线程竞争资源,是能够加上锁的,先来后到;非公平锁
,后续线程没有按照队列形式来拿到锁。在多线程高并发环境下,多线程竞争锁,有一个竞争成功加上锁,成功的线程直接执行方法逻辑;
加锁失败,生成阻塞队列
,存放全部等待线程,等待获取释放锁后的使用权;当前一个使用者释放锁, 队列会唤醒一个线程去竞争资源加锁,以达到线程安全的效果;成功就加锁,失败就再回到阻塞队列。sql
volatile是轻量级的synchronized。锁提供了两种特性,互斥和可见性。所以在保证多线程读写时数据的一致性,可使用同步即synchronized关键字和可见性即volatile。数据库
1.volatile数组
可见性的意思即当一个线程修改了共享变量时,另外一个线程也能读取到这个最新的数值。缓存
对于volatile修饰的变量在进行写操做时,处理器不会直接和内存通讯,会先写入到缓存中。在这个写入缓存的过程当中,用到缓存一致性确保修改的原子性。当缓存回写到内存中时会致使其余处理器对此变量的缓存无效,会从新读取此变量的值。安全
2.synchronized和volatile的区别多线程
1)volatile本质是在告诉jvm当前变量在寄存器中的值是不肯定的,须要从主存中读取,synchronized则是锁定当前变量,只有当前线程能够访问该变量,其余线程被阻塞住.
2)volatile仅能使用在变量级别,synchronized则可使用在变量,方法.
3)volatile仅能实现变量的修改可见性,而synchronized则能够保证变量的修改可见性和原子性.
4)volatile不会形成线程的阻塞,而synchronized可能会形成线程的阻塞.