集合框架,多线程,MYSQL面试题

本文详细解析了Java中的ArrayList、LinkedList、HashMap、HashTable和ConcurrentHashMap等数据结构,探讨了集合框架的线程安全性和性能特点。同时介绍了MySQL数据库的三范式、SQL函数、索引原理、事务与隔离级别,以及多线程中的线程池和锁概念,以及MySQL优化策略。
摘要由CSDN通过智能技术生成

一. 集合框架

ArrayList & LinkedList

  1. 1.

    是否保证线程安全

    ArrayList和linkedList都是不同步的,也就是不保证线程安全
  2. 2.

    底层数据结构

     
    ArrayList底层是Object数组,LinkedList底层使用的是双向循环链表

    2.1 什么是双向链表

     
    双向链表也叫双链表,是链表的一种,它的每个数据节点(Node) 都有两个指针(Object pre; Object next;),分别指向直接后继和直接前驱。所以,从双向链表的任意一个节点开始,都可以很方便的访问它的前驱和后继。一般我们都构造双向循环链表(头尾关联)
  3. 3.

    插入和删除是否受元素位置影响

     
    ArrayList采用数组存储,所以插入和删除元素的时间复杂度受元素位置影响,比如执行add(E e)方法的时候,ArrayList会默认将指定元素追加到列表的末尾,这种时间复杂度就是O(1).但是如果再指定位置插入元素add(int index, E e);时间复杂度就是O(n-i),执行本次操作还需要将集合中第i个和第i个之后的元素向后位移一位
    ​
    LinkedList采用链表存储,所以插入,删除时间复杂度都是近似O(1)
  4. 4.

    是否支持快速随机访问

     
    LinkedList不支持高效的随机元素访问,但是ArrayList实现了 RandomAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素(get(index)方法)
  5. 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. 1.

    线程是否安全: HashMap是非安全的,HashTable是安全的,因为它的内部方法都被synchronize修饰(现在如果需要一个线程安全的集合 更适合使用 ConcurrentHashMap)

  2. 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. 1.

    在多线程修改一个值 a的时候,会将a copy到自己的线程内存空间中(预期值) ,此时预期值就是a , 要修改的值就是a+1的结果,结果就是1(要修改的值), 由于是多个线程,所以每隔线程内部都会得到一个 a=1

  2. 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. 1.

    数据库的三范式是什么

    第一范式: 每个列都不可以再拆分
    第二范式: 非主键列依赖于主键
    第三范式: 非主键列只依赖主键列,不依赖其他非主键
  2. 2.

    mysql中的常用函数’

    count(*/column) : 返回行数
    sum(column): 返回指定列中值的和
    max(column):  返回指定列或表达式中的数值最大值
    min(column):  返回指定列或表达式中的数值最小值
    avg(column):  返回指定列或者表达式中数值的平均值
    date(Expression):  返回表达式所代表的日期值
    ......
  3. 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. 4.

    MyISAM和InnoDB的区别

    MyISAM不支持外键和事务, 不支持哈希索引,支持全文索引,查询速度更优,包括例如count函数的运用更有效率,
    innodb支持哈希索引,不支持全文索引,支持外键和事务了,在处理 update/delete/insert上更优
  5. 5.

    什么是索引

    语法: create index student_unique_ide on student(stu_no) tablespace idx
    索引是一种特殊的文件,他们包含对数据表里所有记录的引用指针
    索引是一种数据结构。 数据库索引是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库表中的数据,索引的实现通常是 B树以及其变种 B+树
    索引就相当于目录。为了方便查找书中的内容。
  6. 6.

    索引有什么优点

    可以大大提高查询效率,这也是创建索引的原因,通过使用索引可以在查询的过程中使用优化隐藏器提高性能。
  7. 7.

    索引有什么缺点

    时间: 创建和维护需要消耗时间,对表的数据进行增加删除修改都需要动态的维护索引,会降低增删改的效率
    空间: 索引需要占用物理空间
  8. 8.

    索引的种类

    1. 唯一索引: 不允许有两行具有相同的值
    2. 主键索引: 维护表与表之间的关系
    3. 聚集索引: 表中行的物理顺序与键值的逻辑(索引)顺序相同 
    4. 非聚集: 表中行的物理顺序与键值的逻辑(索引)顺序不相同 
    5. 复合索引: 多个列组合成索引
    6. 全文索引:为字符串数据进行复杂的 词搜索提供有效支持 
  9. 9.

    索引的使用场景

    1. 当数据多且字段值有相同的值的时候使用 普通索引
    2. 当字段多且字段没有重复的值使用 唯一索引
    3. 当多个字段名经常被用于查询,可以使用 联合索引 
    4. 如果增删改的情况多,不适合使用索引, 索引列如果被修改,就需要重新维护索引
    5. 更新太频繁的字段不适合使用索引
    6. 不会出现在where条件中的字段不应该建立索引
  10. 10.

    索引的数据结构

参考面试宝典 B树和B+树的区别

  1. 1.

    事务的特性 (ACID)& 隔离级别

    参考面试宝典

  2. 2.

    MYSQL有哪些锁

    从锁的类型上来讲,mysql有共享锁和排它锁
    共享锁其实就是读锁, 共享锁可以让多个线程获取同一个锁
    排它锁,其实就写锁。写锁是独占锁,一个锁在某一个时刻只有一个线程能够获取, 也就是互斥锁
  3. 3.

    隔离级别和锁有什么关系

    在读未提交: 读取数据不需要加共享锁,这样就不会跟被修改的数据上的排它锁冲突
    在读已提交: 读操作会加共享锁,但是在语句执行结束以后释放共享锁
    在可重复读: 读操作需要加共享锁,但是在事务提交之前不释放,也就是必须等待事务执行完毕后才释放共享锁
  4. 4.

    查询优化

    1. 优化索引
    2. 避免使用通配符  select *
    3. 避免全表扫描  limit
    4. 在使用连接查询时, 尽量避免过多的表连接
    5. 在使用子查询时,子查询是多个查询语句的拼接,所以单个查询语句都可以遵循查询优化机制,故而子查询的性能优于连接查询。

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值