JAVA
String StringBuilder StringBuffer
String是不可变的
STringBuilder可变, 且不是线程安全的
StringBuffer同StringBuilder类似,但是线程安全的
== 与 equals 方法的区别
== : 如果是基本的数据类型 比较的是值 如果是引用类型,比较的是引用地址
equals : 具体看各个类重写equals方法之后的比较逻辑
ApplicationContext和Beanfactory的区别
CopyOnWriteArrayList底层原理
写的时候会加锁, 且写的时候能够读
Mysql
B树和B+树的区别
Explain语句结果中各个字段分表表示什么
定位了查询慢的SQL之后,我们就可以使用EXPLAIN或DESCRIBE 工具做针对性的分析查询语句。
DESCRIBE语句的使用方法与EXPLAIN语句是一样的,并且分析结果也是一样的。
MySQL中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供它认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)。
这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,对于每个表采用什么访问方法来具体执行查询等等。MySQL为我们提供了EXPLAIN语句来帮助我们查看某个查询语句的具体执行计划,大家看懂EXPLAIN语句的各个输出项,可以有针对性的提升我们查询语句的性能。
EXPLAIN SELECT select_options
或者
DESCRIBE SELECT select_options
MySQL 5.6.3以前只能EXPLAIN SELECT;MYSQL 5.6.3以后就可以 EXPLAIN SELECT,UPDATE,DELETE
在5.7以前的版本中,想要显示 partitions 需要使用 explain partitions 命令;想要显示filtered 需要使用 explain extended 命令。在5.7版本后,默认explain直接显示partitions和 filtered中的信息。
出现的信息:
- 表的读取顺序
- 数据读取操作的操作类型。
- 哪些索引可以使用
哪些索引被实际使用
- 表之间的引用
每张表有多少行被优化器查询
各个字段分别表示什么:
Innodb是如何实现事务的
MySQL慢查询如何优化?
Mysql中的锁
简述MyISAM和InnoDB的区别
Redis和Mysql保证数据一致性
什么是MVCC
MVCC是多版本并发控制 Multi-Version Concurrent Contrl。
它是MySQL中的提高性能的一种方式,配合Undo log 和版本链,替代锁,让不同事物的读-写、写-读操作可以并发的执行,从而提升系统的性能。
MVCC 在 MySQL InnoDB 中的实现主要是为了提高数据库并发性能。一般是在使用读已提交(PEAD COMMITTED)和可重复读(REPEATABLE READ)隔离级别的事务中实现。
用自己的话说就是:
多版本意思是指数据库中一条数据有多个版本同时存在,在某个事务对其进行具体操作的时候,是需要查看这一条记录的隐藏列事务版本的id,比对事务id并根据事物的隔离级别从而去判断是哪个版本的数据。
准确的说,MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突” 这么一个概念。
快照读
就像不加锁的select操作就是快照读,即不加锁的非阻塞读;
快照读的前提就是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;
之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下都避免了加锁操作,降低了开销;
既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。
说白了就是MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读,而非当前读,当前读实际上就是一种加锁的操作,是悲观锁的实现。
索引的基本原理
索引覆盖
雪花算法
Mybaits Plus 的默认的ID生成策略就是雪花算法
最左前缀原则
线程池
线程池基础
创建线程的四种方法:继承Thread接口,实现Runnable接口,实现Callable接口,用线程池
不用Excutors创建线程池的原因,参数中使用的任务队列是链表,可以无限添加任务,会占用大量的内存。
线程池的五种状态 : Running , shutdown > 不接受新任务 , 但是会处理完任务队列中的任务 , STOP shutdownNow > 不接受新任务,且不处理剩余的任务 , TIDYING > 线程停止后的状态, 并且会调用terminated(),留用于拓展 , TERMINATED > terminated()调用完进入
Sychronized 和 ReentrantLock 有哪些不同点
公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁。非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁。
锁升级,是将众多细粒度锁转换为较少的粗粒度的锁的过程,以削减系统开销。当事务超过它的升级极限时,Microsoft® SQL Server™ 2000 自动将行锁和页锁升级为表锁。例如,当事务从表中请求行时,SQL Server 自动获取受影响的行上的锁,并在包含这些行的页和表或者索引上放置更高级别的意向锁。当事务控制的锁数量超过了它的极限时,SQL Server 会试图将表上的意向锁更改为更强的锁(例如,将意向排它 (IX) 锁更改为排它 (X) 锁)。获取更强的锁后,表事务持有的所有页级锁和行级锁都被释放,从而削减锁的开销。
SQL Server 可以为同一查询选择行和页锁定,例如,在索引上放置页锁(如果在非聚集的索引节点中选定了足够的邻接键来满足查询)及在数据上放置行锁。以减少必须进行锁升级的可能性。
锁升级极限是由 SQL Server 动态确定的,无须进行配置。
SQL Server 可以动态升级或降级锁粒度或锁类型。例如,如果更新获取大量行锁而阻塞了表的大部分,将行锁升级到表锁。如果获取了表锁,将释放行锁。SQL Server 2000 很少需要升级锁;查询优化器在编译执行计划时通常选择正确的锁粒度。
ThreadLocal有哪些应用场景?它底层是如何实现的?
ReentrantLock分为公平锁和非公平锁,那底层分别是如何实现的?
锁升级
Tomcat中为什么要用自定义类加载器
Redis
Redis有哪些数据结构,分别有哪些典型的应用场景
分布式锁的使用场景是什么?有哪些实现方案?
缓存穿透、缓存击穿、缓存雪崩分别是什么?
RDB和AOF
redis为什么是单线程的
因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
详细原因:
1)不需要各种锁的性能消耗
Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除
一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
2)单线程多进程集群方案
单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。
所以单线程、多进程的集群不失为一个时髦的解决方案。
3)CPU消耗
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。
但是如果CPU成为Redis瓶颈,或者不想让服务器其他CUP核闲置,那怎么办?
可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程上就可以了。
Spring
Spring事务的传播机制
SpringBoot是如何启动Tomcat的
Spring Boot 中常用注解及其底层实现
Spring容器启动流程是怎样的
Spring 事务什么时候会失效
Spring用到了哪些设计模式——
Spring中的Bean是线程安全的吗
Spring中的Bean创建的生命周期有哪些步骤
Spring中的事务是如何实现的
单例Bean和单例模式的区别
IOC容器
控制反转:
控制:控制对象的创建、控制对象内属性的赋值
反转:表示一种对对象控制权的转移
Mybaits的优缺点
基础算法
二分查找
前提- 有序数组A
定义左边界l 右边界r
mid = (l+r) /2
如果a[mid] == 需要查找的数 则返回索引mid
如果大于或者小于 则按照实际升序或者降序情况 重定查找边界 [l,mid-1] 或[mid+1,r]
中间值 会因左右数太大相加而溢出变成负数
mid = l + (r-l)/2
>>>无符号右移:无论最高位是什么 ,右移后,都补0;而>>右移补0还是补1由最高位确定。
mid = (l+r) >>>2
13 mid = 0 + 12 /2 = 6 奇数的二分取中间 偶数的二分取中间靠左
31 - 45 - 49 - 48 比较4次
log2 128 = 7 +1
Arrays.binarySearch
冒泡排序
核心 - 比较前后 a[i] a[i+1] 视情况 ,如果出现大于或者小于,则进行交换
优化
因为第二层沉下去了,在i的基础上,则是排序好的次数,所以i+1轮 i+1个元素不需要再进行比较
排序好了 ,则不需要再进行排序遍历,设置一个bool变量,如果一轮冒泡没有交换,则已经是有序的数组了,不需要再进行,直接break
记录最后一次交换的下标,则此下标之后的元素都是有序的,直接作为下一次的交换上限
2 7 11 15
1 4 10 11
2 7 11 15