ArrayList的底层原理,和LinkedList的区别
① 数据结构不同
ArrayList是Array(动态数据数组)的数据结构,LinkedList是Link(链表)的数据结构。
② 效率不同
随机访问时List时,ArrayList比LinkedList的效率要高,因为LinkedList是线性的数据存储,需要移动指针从前往后依次查找。
HashMap的底层原理,和HashTable的区别,和HashSet的区别
HashMap底层原理:HashMap的数据结构为 数组+(链表或红黑树)
put的实现原理:
通过key的hashcode()方法得到hash值,通过hash值和数组长度得到数组的下标。
如果下标的位置上没有任何元素,就把Node添加到这个位置上。
如果下标的位置上有链表,就会拿着key和链表上每个节点的k进行equals。
如果所有的equals方法都是返回false,那么这个新节点将被添加到链表的末尾。
如果其中一个equals返回了true,那么这个节点的value就会被覆盖。
get的实现原理:
先调用k的hashcode()方法得到hash值,通过hash值和数组长度得到数组下标。
如果这个位置上什么都没有,返回null。
如果这个位置上有单向链表,拿着k和单向链表中的每一个节点的k进行equals,如果equals方法都返回了false,返回null;如果其中一个节点的k和节点参数的k进行equals为true,那么返回该节点的value值。
hashmap和hashtable的区别:
① hashmap线程不安全,hashtable是线程安全的(方法都加上了synchronized)
② hashmap可以支持null(key为null or value为null),hashtable都不支持。
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
hashmap和hashset的区别:
① hashset使用add()方法添加元素,实际上还是调用hashmap的put方法,添加的元素放在key中,value都是统一的一个固定对象。
② add元素时,会判断key是否存在,如果key存在则修改Entry节点value的值,如果key不存在,则插入。
private static final Object PRESENT = new Object(); public boolean add(E var1) { return this.map.put(var1, PRESENT) == null; }
ConcurrentHashMap的底层原理,和HashTable的区别
concurrentHashMap特性and原理:
特性:
concurrentHashMap是不允许key/value为空
原理:
使用segment继承了ReetrantLock,使用了分段锁技术来保证线程安全
将数据分成一段一段的储存,然后给每一段数据配一把锁,多线程访问不同段的数据时,就不会存在锁竞争。
jdk1.8之前:(Segments数组+ HashEntry数组 + 链表)
每一个segment就是一个HashEntry<K,V>[] table,table中的每一个元素本质上都是一个HashEntry的单向队列(原理和hashMap一样)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dJWxKKTF-1631955380285)(C:\Users\50470\AppData\Roaming\Typora\typora-user-images\image-20210802160651351.png)]
put元素:
concurrentHashMap不允许key/value为空,通过key的hashcode()方法获取hash值,通过segmentShift 和 segmentMask去定位segment数组的下标。
同时因为segments是一个数组,然后每个元素里面又嵌套一个数组,每次put元素的时候,需求计算两次hash值,第一次计算segment[]数组下标,第二次计算HashEnter数组下标。
get元素:
get方法无需加锁,涉及到的共享变量都使用volatile修饰,volatitle可以保证内存的可见性,切防止了指令重新排序,不会读取到过期数据。
jdk1.8之后:(数组 + 链表 + 红黑树 + cas + synchronized)
抛弃了segments数组,去掉了分段锁的方案,改用了和HashMap一样的结构操作,也就是数组+ 链表 + 红黑树,在并发方面,使用cas + synchronized的方式保证数据的一致性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xjLrd1Tw-1631955380288)(C:\Users\50470\AppData\Roaming\Typora\typora-user-images\image-20210802161950364.png)]
链表转为红黑树的条件:
① 数组中任意一个链表长度超过8个
② 数组长度大于64个
jdk1.7和1.8中hashMap的区别
① 数据插入方式不同
jdk1.7用的头插法,jdk1.8用的是尾插法
头插法容易出现逆序且环形链表死循环问题;尾插法能够避免。
② 数据结构不同
jdk1.7的时候使用的是数组 + 单向链表数据结构;jdk1.8使用的是数组 + 链表 + 红黑树(当链表长度达到8的时候,自动的转变为红黑树)
③ 扩容方式不一样
④ 下标计算不一样
volatile、synchronized、Lock,ReenTrantLock的底层原理和区别
volatile 与 synchronized
① volatile仅能在变量级别使用,synchronized可以在变量和方法。
② volatile本质上是告诉jvm当前变量是不确定的,需要从主内存中取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞。
③volatile仅能实现变量的可见性,synchronized可以保证变量的可见性和原子性。
④volatile不会造成线程阻塞,synchronized可能回造成线程阻塞。
synchronized 与 lock
① Lock是一个接口,synchronized 是java中的关键字。
②synchronized 在发生异常时回自动释放线程占用的锁。lock在发生异常时,如果没有手动调用unlock(),很可能造成死锁,因此使用lock需要在finnally中释放锁。
③lock可以知道有没有成功的获取到锁,synchronized 无法判断。
ReenTrantLock 与 synchronized
① ReenTrantLock 和synchronized都是独占锁,synchronized加锁解锁是隐式的,操作简单,但不够灵活。
ReenTrantLock 需要手动加锁解锁,且解锁尽量放在finally中,确保能正确的释放锁。
② synchronized 和 ReenTrantLock 都是可重入锁,ReentrantLock可重入要确保获取锁的获取次数和锁的释放次数要一样。
③ synchronized默认为非公平锁,ReenTrantLock 可实现非公平锁和公平锁。
CAS和AQS的底层原理和区别
CAS:比较和交换,CAS是一个原子性操作,要么成功要么失败,CAS不需要加锁,是一种乐观锁的方式,如果CAS操作失败,会不断重试直到成功。
CAS无法保证代码块的原子性,CAS只能保证单个变量的原子性操作,如果要保证多个变量的原子性操作就要使用悲观锁。
AQS:抽象的队列同步器,是一个同步器框架。
乐观锁和悲观锁的区别
乐观锁:每次拿数据的时候都认为别人不会修改,不会上锁,但是在更新的时候会判断一下再次期间别人有没有取更新数据,可以使用版本号等机制。
乐观锁多适用于多读的场景。
悲观锁:每次拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁,其他人想拿到这个数据就会block直到获取到锁,在操作之前先上锁。
悲观锁多使用与多写的场景。
JVM与Java的内存模型
String的常用方法,以及为什么不能修改,继承
indexOf(),length(),String被final修饰,无法继承和修改。String中的方法,都会重新返回一个new String()的对象,不会对原本的数据进行改变。
对事物的传播行为和理解
Spring七种事物传播行为:
① required,必须,默认值,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务。
② supports,支持,A如果有事务,B将使用该事务;如果A没有事务,B将以非事务执行。
③ mandatory,强制,A如果有事务,B将使用该事务;如果A没有事务,B将抛异常。
④ requires_new,必须新的,如果A有事务,将A的事务挂起,B创建一个新的事务;如果A没有事务,B创建一个新的事务。
⑤ not_supported ,不支持,如果A有事务,将A的事务挂起,B将以非事务执行;如果A没有事务,B将以非事务执行。
⑥ never,从不,如果A有事务,B将抛异常;如果A没有事务,B将以非事务执行。
⑦ nested ,嵌套,如果A当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
ThreadLocal的理解和应用
ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal 的经典使用场景是数据库连接和 session 管理等。
接口开发的相关问题
① 规范接口文档,请求参数以及返回数据要详细说明。
② 接口的安全性
反射的原理
① 对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法。
spring初始化bean的流程
SpringAOP的实现方式
Spring如何解决循环依赖
SpringCache的原理优点和缺点
Spring的常用注解
SpringMVC的流程
@RequestBody如果不加会有什么后果
SpringBoot是什么
SpringCloud常用组件
redis的作用
redis持久化策略(RDF和AOF各自特点)
redis为什么单线程这么快?其他应用为什么不采用单线程?
NIO和BIO的特点
redis过期key的处理策略
mysql的索引结构
hash索引的特点
B+树索引的特点
select xx for update 会导致行锁还是表锁,为什么?
业务主键和逻辑主键的区别
慢查询怎么排查
怎么优化SQL
单表的数据量过大怎么处理
索引失效的场景有哪些,怎么解决like导致索引失效
1in和extis的区别
in使用场景和带来的问题
对事物的理解
哪几种存储引擎,各有什么特点
给出具体场景,这个SQL如何编写(主要是关联查询、分组、分页)
表与表之间是多对多的关系,如何解决
rockmq、kafka、rabbitmq的特点
怎么保证消息的可靠性
万一挂了咋办?
如何保证顺序消费
linux
1.linux常用命令有哪些(每次都是我刚开始说面试官就喊停,只有1个面试官让我说了半个小时,口都说干了,老师讲课带水杯是有原因的)
2.线上出了问题,会用到哪些linux命令排查
3.解压缩相关的命令
4.常用的加密算法
5.对称加密和非对称加密的特点
6.md5的加密是可逆的吗?
其他
1.k8s的作用
2.jenkins的流程
3.docker的作用
4.docker的常用命令
6.对于出差的看法
7.对于加班的看法
如何解决**
rockmq、kafka、rabbitmq的特点
怎么保证消息的可靠性
万一挂了咋办?
如何保证顺序消费
linux
1.linux常用命令有哪些(每次都是我刚开始说面试官就喊停,只有1个面试官让我说了半个小时,口都说干了,老师讲课带水杯是有原因的)
2.线上出了问题,会用到哪些linux命令排查
3.解压缩相关的命令
4.常用的加密算法
5.对称加密和非对称加密的特点
6.md5的加密是可逆的吗?
其他
1.k8s的作用
2.jenkins的流程
3.docker的作用
4.docker的常用命令
6.对于出差的看法
7.对于加班的看法
8.对瀑布开发,敏捷开发,迭代开发的看法(对比一下优缺点)