一. 集合框架
ArrayList & LinkedList
-
1.
是否保证线程安全
ArrayList和linkedList都是不同步的,也就是不保证线程安全
-
2.
底层数据结构
ArrayList底层是Object数组,LinkedList底层使用的是双向循环链表
2.1 什么是双向链表
双向链表也叫双链表,是链表的一种,它的每个数据节点(Node) 都有两个指针(Object pre; Object next;),分别指向直接后继和直接前驱。所以,从双向链表的任意一个节点开始,都可以很方便的访问它的前驱和后继。一般我们都构造双向循环链表(头尾关联)
-
3.
插入和删除是否受元素位置影响
ArrayList采用数组存储,所以插入和删除元素的时间复杂度受元素位置影响,比如执行add(E e)方法的时候,ArrayList会默认将指定元素追加到列表的末尾,这种时间复杂度就是O(1).但是如果再指定位置插入元素add(int index, E e);时间复杂度就是O(n-i),执行本次操作还需要将集合中第i个和第i个之后的元素向后位移一位 LinkedList采用链表存储,所以插入,删除时间复杂度都是近似O(1)
-
4.
是否支持快速随机访问
LinkedList不支持高效的随机元素访问,但是ArrayList实现了 RandomAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素(get(index)方法)
-
5.
内存占用空间
都有空间浪费的情况,ArrayList的空间浪费体现在List列表的结尾一般都会预留空间,LinkedList的每一个元素都要消耗比ArrayList更多的空间,因为要存放后继以及前驱
HashMap的底层实现
HashMap主要由数组和链表组成,它不是线程安全的(风险)。核心的点就是put插入数据的过程,get查询数据的过程和扩容,往map插入元素的时候首先通过对key hash然后与数组长度-1与运算((n-1)&hash),等同于取模, 找到数组中的位置后,没有元素就存入,反之则判断key是否相同,key相同就覆盖,否则就插入到链表的尾部,如果链表的长度超过8,则会转换为红黑树,最后判断数组长度是否超过默认长度*负载因子也就是12,超过则进行扩容,扩容的过程就是对key进行重新计算hash,然后把数据拷贝到新的数组
HashTable和 HashMap 的区别
-
1.
线程是否安全: HashMap是非安全的,HashTable是安全的,因为它的内部方法都被synchronize修饰(现在如果需要一个线程安全的集合 更适合使用 ConcurrentHashMap)
-
2.
效率: 因为上锁的缘故,HashTable的性能要差一些。 目前HashTable基本被淘汰了
ConcurrentHashMap和HashTable的区别
-
•
底层数据结构: ConcurrentHashMap的底层和HashMap一样都是 数组+链表/红黑树 , HashTable是数组+链表 数组是主体,链表是为了解决hash冲突问题
-
•
实现线程安全的方式:ConcurrentHashMap在1.8以前使用的 (分段锁 ),每一把锁只锁定容器中一部分数据,这样多线程访问容器的时候就可能减少锁竞争的概率,提高并发 , 1.8 之后采用 Node数组+链表+红黑树的数据结构来实现,并使用 sychronized 和 CAS 来操作
什么是CAS
CAS 称为比较并交换,也称为无锁,如果我们在修改一个变量的值的时候希望其安全,一般都会通过加锁的方式实现,但是加锁实际上是一种很重的行为
int number = 0;
public synchronized void num(){
number++;
}
上面通过加锁解决并发问题实际上是一种悲观锁的思想,它总是认为数据会被修改,所以在操作数据的代码块之前上锁,操作完毕再释放。
而无锁算法,比如CAS,它会认为别人去拿数据的时候不会修改,但是在修改的时候会判断一下数据的状态,这样读多的情况下性能就可以有效的提高。
CAS 概念
CAS 是 compare and swap 比较并交换,是实现并发算法常用的一种技术,主要是通过处理器的指令来保证原子性,它包含3个操作数
1. 变量内存地址 V
2. 旧的预期值 A
3. 准备设置的新值 B
当执行CAS指令时,只有当V等于A时,才会用B去更新V的值否则就不更新
举例说明
比如a+1的操作,a 默认=0
-
1.
在多线程修改一个值 a的时候,会将a copy到自己的线程内存空间中(预期值) ,此时预期值就是a , 要修改的值就是a+1的结果,结果就是1(要修改的值), 由于是多个线程,所以每隔线程内部都会得到一个 a=1
-
2.
接着就会执行比较并交换,让线程中的预期的值和主内存中的a进行比较,如果相同就提交上去,如果不相同说明a的值已经被别的线程修改过了,然后重新获取a的值,然后重复这一操作,这种重复操作我们称为自旋
二 多线程
线程池的常用参数有哪些
-
•
corePoolSize: 核心线程数,一直存活的线程数量
-
•
maximumPoolSize: 线程池允许的最大线程数量
-
•
keepAliveTime: 超过核心线程数的线程空闲后的最大存活时间
-
•
unit: 时间单位
-
•
workQueue: 任务队列
-
•
threadFactory :线程工厂,创建新线程
-
•
RejectedExecutionHandler : 拒绝策略
当提交一个任务到线程池,它的执行流程
如果当前正在执行的线程数量小于核心线程数就会调用 addworker()
将任务交给线程池处理,立即执行当前任务,如果工作线程数大于等于核心线程数,则将任务加入到工作队列,如果工作队列已满,则交给线程池判断当前线程数量是否已经大于等于最大线程数,如果小于则创建新的线程运行任务,反之拒绝该任务【执行拒绝策略】
synchronized的作用
保证在并发下被标记synchronized的方法或者代码块同一时间只有一个线程可以执行
Volatile关键字的作用
volatile关键字用于保证可见性,当一个共享变量被volatile修饰时,它会保证修改的值被理解更新到主内存。所以经常配合CAS使用,保证原子性,例如juc的atomic包下的原子类,会结合volatile+cas实现原子操作
volatie既然能保证可见,为何不能单独保证原子性
写入主内存的操作如果不判断也不具备原子性,而volatile只能保证写入操作结束的可见性
synchronized和lock的区别
synchronized是关键字, Lock是接口,Lock接口有多个实现类,对比synchronized做了更多的扩展,比如Lock提供了尝试机制用于避免死锁,(tryLock)
什么是乐观锁,什么是悲观锁
乐观锁: 对于并发间操作产生的线程安全问题持乐观态度,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么应该有相应的重试逻辑。(读多写少)
悲观锁:
悲观锁认为竞争总是会发生,因此每次对资源进行操作,都会持有一个独占的锁,比如synchronized
三. MySQL
-
1.
数据库的三范式是什么
第一范式: 每个列都不可以再拆分 第二范式: 非主键列依赖于主键 第三范式: 非主键列只依赖主键列,不依赖其他非主键
-
2.
mysql中的常用函数’
count(*/column) : 返回行数 sum(column): 返回指定列中值的和 max(column): 返回指定列或表达式中的数值最大值 min(column): 返回指定列或表达式中的数值最小值 avg(column): 返回指定列或者表达式中数值的平均值 date(Expression): 返回表达式所代表的日期值 ......
-
3.
字符串类型有哪些,有什么区别,什么时候该选择什么类型
包括varchar,char,text,blob varchar:用于存储可变字符串,它比定长类型更加节省空间,varchar使用额外1或2个字节存储字符串长度。当字段长度小于255字节时,使用1字节表示,否则使用2字节表示,当Varchar存储的内容超出设置的长度时,内容会被截断 char: char是定长的,根据定义的字符串长度来分配空间,char会根据需要使用空格来填充方便进行比较,char适合存储很短的字符串,或者所有值都接近一个长度 比较char和varchar 对于经常变更的数据来说,char比varchar更好,因为char不容易产生碎片。对于非常短的列,char比varcahr在存储空间上更有效率。 text/blob类型:尽量少用,因为查询时会使用临时表,导致额外的性能开销
-
4.
MyISAM和InnoDB的区别
MyISAM不支持外键和事务, 不支持哈希索引,支持全文索引,查询速度更优,包括例如count函数的运用更有效率, innodb支持哈希索引,不支持全文索引,支持外键和事务了,在处理 update/delete/insert上更优
-
5.
什么是索引
语法: create index student_unique_ide on student(stu_no) tablespace idx 索引是一种特殊的文件,他们包含对数据表里所有记录的引用指针 索引是一种数据结构。 数据库索引是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库表中的数据,索引的实现通常是 B树以及其变种 B+树 索引就相当于目录。为了方便查找书中的内容。
-
6.
索引有什么优点
可以大大提高查询效率,这也是创建索引的原因,通过使用索引可以在查询的过程中使用优化隐藏器提高性能。
-
7.
索引有什么缺点
时间: 创建和维护需要消耗时间,对表的数据进行增加删除修改都需要动态的维护索引,会降低增删改的效率 空间: 索引需要占用物理空间
-
8.
索引的种类
1. 唯一索引: 不允许有两行具有相同的值 2. 主键索引: 维护表与表之间的关系 3. 聚集索引: 表中行的物理顺序与键值的逻辑(索引)顺序相同 4. 非聚集: 表中行的物理顺序与键值的逻辑(索引)顺序不相同 5. 复合索引: 多个列组合成索引 6. 全文索引:为字符串数据进行复杂的 词搜索提供有效支持
-
9.
索引的使用场景
1. 当数据多且字段值有相同的值的时候使用 普通索引 2. 当字段多且字段没有重复的值使用 唯一索引 3. 当多个字段名经常被用于查询,可以使用 联合索引 4. 如果增删改的情况多,不适合使用索引, 索引列如果被修改,就需要重新维护索引 5. 更新太频繁的字段不适合使用索引 6. 不会出现在where条件中的字段不应该建立索引
-
10.
索引的数据结构
参考面试宝典 B树和B+树的区别
-
1.
事务的特性 (ACID)& 隔离级别
参考面试宝典
-
2.
MYSQL有哪些锁
从锁的类型上来讲,mysql有共享锁和排它锁 共享锁其实就是读锁, 共享锁可以让多个线程获取同一个锁 排它锁,其实就写锁。写锁是独占锁,一个锁在某一个时刻只有一个线程能够获取, 也就是互斥锁
-
3.
隔离级别和锁有什么关系
在读未提交: 读取数据不需要加共享锁,这样就不会跟被修改的数据上的排它锁冲突 在读已提交: 读操作会加共享锁,但是在语句执行结束以后释放共享锁 在可重复读: 读操作需要加共享锁,但是在事务提交之前不释放,也就是必须等待事务执行完毕后才释放共享锁
-
4.
查询优化
1. 优化索引 2. 避免使用通配符 select * 3. 避免全表扫描 limit 4. 在使用连接查询时, 尽量避免过多的表连接 5. 在使用子查询时,子查询是多个查询语句的拼接,所以单个查询语句都可以遵循查询优化机制,故而子查询的性能优于连接查询。