线程安全的集合
ConcurrentHashMap:线程安全的HashMap
CopyOnWriteArrayList: 线程安全的List,在读多写少的场合性能非常好,远远好于Vector
ConcurrentLinkedQueue:高效的并发队列,使用链表实现。可以看作一个线程安全的LinkedList,这个是非阻塞队列
synchronized和reentrantlock区别
两者都是可重入锁,指的是线程可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象还有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果是不可重入锁的话,就会造成死锁。
synchronized是依赖于JVM实现的,而ReentrantLock是JDK层面实现的
reentrantLock增加了高级功能,主要包含三点:等待可中断,可实现公平锁,可实现选择性通知
面向对象的三大特性
封装:封装是指把一个对象的状态信息隐藏在对象内部,不允许外部对象直接访问对象的内部信息,但是可以提供一些可以被外界访问的方法来操作属性
继承:不同类型的对象,相互之间经常有一定数量的共同点
多态:表示一个对象具有多种状态,具体表现为父类的引用指向子类的实例
为什么HashMap长度为2的幂次方
取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说hash%length==hash&(length-1)的前提是length是2的n次方),并且采用二进制位操作&相当于%能够提高运算效率
ArrayList扩容
以无参构造方法创建ArrayList时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。不断添加元素,直到添加到第11个元素时,才会进行扩容。ArrayList每次扩容会变为原来容量的1.5倍左右
Redisson可重入锁的原理
在redisson中,使用一个hash结构来存储锁,其中key表示该锁是否存在,field标识线程的持有者,value为锁的重入次数
判断锁的流程:先判断锁是否存在,如果锁不存在,创建一把新的锁并设置重入次数为1,设置锁的过期时间。如果锁已经存在,继续判断这把锁的field和自身线程标识是否一致,锁的重入次数+1,刷新锁的超时时间。锁的filed与自身线程标识不一致,说明锁已经被别人持有,返回锁的剩余时间
线程池的核心线程参数设置为0,任务是否会被执行
当核心线程数为0时,当来了一个任务之后,会先讲任务添加到任务队列,同样也会判断当前工作的线程数是否为0,如果为0,则会创建线程来执行线程池的任务。
核心线程数和最大线程数保持一致的原因
线程池在任何时刻都将保持固定数量的线程,不会动态增加或减少,节约系统资源,避免频繁创建和销毁线程带来的开销。在高并发场景,过多的线程可能会造成系统负载过重,甚至引发性能下降,系统崩溃等问题,而线程固定则有效避免
幻读的解决
对于快照读:可重复读隔离级别是由MVCC(多版本并发控制)实现的,实现的方式是开始事务后执行begin语句后,在执行第一个查询语句后,会创建一个read view,后续的查询语句利用这个Read View,通过这个Read View就可以在undo log版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,即使中途有其他事务插入新纪录,是查询不出来这条数据的,所以就很好的避免幻读问题
对于当前读:mysql里除了普通查询是快照读,其他都是当前读,比如update,insert,delete,这些语句执行前都会查询最新版本的数据。引入间隙锁,即范围id为(3,5)间隙锁,其他事务就无法插入id=4的这条记录,这样就有效防止幻读现象的发生
令牌桶算法
请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃,我们根据限流大小,按照一定的速率往桶里添加令牌。如果桶装满了,就不能继续往里面继续添加令牌了。他的优点是可以限制平均速率和应对突然激增的流量,可以动态调整生成令牌的速率。缺点是如果令牌产生速率和桶的容量设置不合理,可能会出现问题比如大量请求被丢弃,系统过载。