云析面试讲解公开课(如何提升offer命中率)2018-12-23

集合相关

  1. 集合相关异常,以及使用各集合间的优缺点?
  • 临时解决方案:百度、咨询同事、快速界解决问题,避免影响项目进度;
  • 解决后的问题反思:
    ArrayList是单线程,非线程安全,需要手动加锁实现同步lock或sychornized;因为代码不方便重用,CopyOnWriteArrayList,它底层是:写加锁,ReentrantLock,读不加锁;ReentrantLock,基于AQS同步,它的公平锁和非公平锁AQS的基础又是CAS区别ReentrantLock和sychornized,和jdk关键字优化有关。
    CopyOnWriteArrayList底层数组由volatile修饰,保证内存可见性,这里涉及到重排序happen-beforeCAS内存屏障注意原子类型,底层就是volatile修饰的。CAS类似数据库中的乐观锁
    CopyOnWriteArrayList的使用场景:读多写少的场景,避免大量临时数组产生(因为每次写的时候,需要两个数组,写操作并发高,导致新生代产生大量临时数组,需要大量GC)、黑/白名单(利用分布式Nginx实现ip黑名单,限流,负载均衡,反爬虫),同包下还有ConcurrentHashMap7与8的Hashmap和ConcurrentHashMap区别

保证思路连续性

  • 一些常见问题:ArrayList的坑、集合优缺点、集合中常见异常、ArrayList能不能在多线程中使用
    ConcurrentModificationException并发修改异常产生于iterator迭代遍历ArrayList,删除一个元素,产生异常,for/foreach也是,expectedModCount表示修改次数期望值,初始值与modCount相等,但是修改集合成员时,modCount会变化,当两者不相等是,抛出这个异常所以需要移除时不能使用list.remove(xxx),而是使用iterator.remove(),因为这个方法会设置那两个参数相等。

说出在什么场景下出现异常(发现问题能力)、说出异常原因(分析问题能力)、说出解决方案(解决问题能力)、对一个小问题的扩展和延伸(总结问题能力)
示例:发现问题——ArrayList遍历出现异常、分析问题——找到源码原因、解决问题——使用迭代器remove方法可以避免、总结问题——多线程场景下迭代器remove方法产生问题引出并发容器
引出CopyOnWriteArrayList,在查看mysql驱动程序类的时候Driver中发现的

  • 项目中的例子:
  1. CopyOnWriteArrayList原理
  • java.util.concurrent包、字面意思write写操作需要copy、任何可变操作(add,set,remove等操作)伴随复制动作
  • 源码浅析
    添加元素——add(E e)
lock.lock();  //加锁,保证线程安全
Arrays.copyOf();  //拷贝出新数组 private volatile transient Object[] array;
lock.unlock();  //finally中解锁,防止出现异常导致锁不释放
/**
* 大致流程都是 先lock一下保证线程安全,拷贝出新数组,操作,修改原数组引用指向新数组,unlock解锁
* 高并发读请求,走的是旧数组。
*/
  1. CopyOnWriteArrayList面试关键点
  • 写时复制机制
  • 写操作加锁/解锁
  • 读操作不需要几所
  • 体现读写分离的思想
  • 体现最终一致性思想
  • 在JDBC驱动程序源码中广泛使用
  • 使用场景:读多写少场景——黑名单、白名单、商品类目
  1. 延伸至 volatile关键字
    volatile是保证线程内存可见性 ,区别于加锁。
    volatile通过JVM底层一些指令,例如:happen-before规则,内存屏障等技术,保证cpu0放入到memory内存中,执行jvm中指令,强制硬件层面上,其他cpu的cache缓存为无效状态,强制从memory中获取新值,放到各自的缓存中进行计算。"大致是清其他cpu缓存,再重新拿缓存"

  2. 延伸至 CAS原子类型操作
    CAS(Compare and Swap)
    原子类型:保证操作都是线程安全的。
    例如:AtomicInteger 底层有一个 private volatile int value; //实际就是int + volatile修饰

  • CAS有三个操作数
    内存值V旧的预期值A要修改的新值B
    当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
  1. 延伸至 乐观锁
  2. 延伸至 锁
    Synchronized是依赖于JVM实现的(操作系统实现)、ReentrantLock是JDK实现的(开发者实现)、两者性能相当
  • 常见的ReentrantLock 重入锁:同一时间,只有一个线程可以使用临界资源;公平锁是若是同一线程竞争资源,是可以加上锁的,先来后到;非公平锁,后续线程没有按照队列形式来拿到锁。
    图

在多线程高并发环境下,多线程竞争锁,有一个竞争成功加上锁,成功的线程直接执行方法逻辑;
加锁失败,生成阻塞队列,存放所有等待线程,等待获取释放锁后的使用权;当前一个使用者释放锁, 队列会唤醒一个线程去竞争资源加锁,以达到线程安全的效果;成功就加锁,失败就再回到阻塞队列。

  1. sychornized 和 volatile关键字

volatile是轻量级的synchronized。锁提供了两种特性,互斥和可见性。因此在保证多线程读写时数据的一致性,可以使用同步即synchronized关键字和可见性即volatile。

1.volatile

可见性的意思即当一个线程修改了共享变量时,另一个线程也能读取到这个最新的数值。

对于volatile修饰的变量在进行写操作时,处理器不会直接和内存通信,会先写入到缓存中。在这个写入缓存的过程中,用到缓存一致性确保修改的原子性。当缓存回写到内存中时会导致其他处理器对此变量的缓存无效,会重新读取此变量的值。

2.synchronized和volatile的区别

1)volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
2)volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
3)volatile仅能实现变量的修改可见性,而synchronized则可以保证变量的修改可见性和原子性.
4)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.

互联网公司常见架构

图

猜你喜欢

转载自blog.csdn.net/weixin_42838993/article/details/85225440