面试题——靖安科技

目录

1.String、StringBuffer、StringBuilder的区别

2.为什么重写equals需要重写hashCode

3.描述一下HashMap

4.多线程的实现方式

5.描述一下乐观锁(CAS算法)

6.类加载双亲委派模型机制

7.四种事务隔离级别

8.Redis持久化机制有哪些,各有什么优缺点

9.描述IOC和AOP

10.Spring MVC启动流程

11.生成分布式ID的方式

12.仿百度网盘的上传功能(个人项目,不予介绍)

13.介绍zk生成ID生成器(个人项目,不予介绍)

14.数据库中有1000w的数据,而Redis只有50w数据,如何保证redis中10w数据都是热点数据

15.如何加快MySQL处理速度 

16.MySQL建表原则

17.描述悲观锁


1.String、StringBuffer、StringBuilder的区别

        1.可变性:String类因为用final修饰,所以String对象不可变;StringBuffer和StringBuilder继承自AbstractStringBuilder,没有final修饰符,所以这两种是可变的;

        2.线程安全性:String因为不可变,可以理解为是一种常量,所以线程安全;StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以线程安全;StringBuilder没有对方法加同步锁,所以是非线程安全的。

2.为什么重写equals需要重写hashCode

        1.保证是同一个对象,如果重写equals不重写hashCode,会出现equals相等的对象,hashCode不相等的情况;

        2.使用hashCode提前校验,可以避免每一次比对都调用equals方法,提高效率。

        ps:hash类存储结构添加元素时会有重复性校验,校验方式就是先取hashCode判断(找到对应的位置,该位置可能存在多个元素),如果地址上没有值,就直接插入,否则再取equals方法比较(缩小比较范围,高效判断),最终判定该存储结构中是否有重复元素。

3.描述一下HashMap

        1.HashMap的数据结构:jdk1.7之前是数组+链表,jdk1.8后是数组+链表+红黑树。数组的特点是查询效率高,链表的特点是插入删除效率高;

        2.HashMap默认采用数组+单链表方式存储元素,当元素出现哈希冲突时,会存储到该位置的单链表中。但是单链表不会一直增加元素,当元素个数超过8个时,会尝试将单链表转化为红黑树存储。但是在转化前,会再判断一次当前数组的长度,只有数组长度大于64才处理。否则,进行扩容操作;

        3.HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap;

        4.HashMap最多只允许一条记录的键为null,允许多条记录的值为null;

        5.根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。

4.多线程的实现方式

        1.继承Thread类;

        2.实现Runable接口;

        3.实现Callable接口通过FutureTask包装器创建Thread线程;

        4.使用线程池。

5.描述一下乐观锁(CAS算法)

        1.乐观锁总是假设最好的情况,每次去拿数据都不会被修改,不进行上锁操作,只在更新时去判断在此期间数据有没有被更新;

        2.适用于多读的情景,可以提高吞吐量;

        3.乐观锁的实现方式有两种,一种是版本号机制,一般是在数据表中加一个version字段,被修改时,version+1。当线程更新数据时,会读取version,提交更新的时候,将刚刚读到的version和现在数据库中的version进行比较,相等才更新,否则重试,直到更新成功;一种是CAS算法,CAS算法是一种无锁算法,涉及到三个操作数,需要读写的内存值V,进行比较的值A,拟定写入的新值B,当且仅当V=A时,CAS更新V为B,否则不断重试,即CPU去更新一个值,如果想改的值不是原来的值,操作就会失败。

        4.CAS会产生ABA问题,即V初次读到为A,准备赋值时也是A,但是在这中间很可能被改为B之后又改回了A,那么CAS会误认为从未被修改。

6.类加载双亲委派模型机制

        当一个类收到了类加载器请求时,自己不先去加载,而是委派给父类,由父类加载,如果此时父类不能加载,则反馈给子类,由子类去完成类的加载。

7.四种事务隔离级别

        1.读未提交

        2.读提交

        3.可重复读

        4.可串行化

8.Redis持久化机制有哪些,各有什么优缺点

        定义:

        1.RDB:Redis默认的持久化方式。按一定时间周期策略将内存数据以快照形式保存到硬盘的二进制文件dump.rdb中。

        2.AOF:将每一个收到的写命令通过Write函数追加到aof文件最后,类似于MySQL的binlog,Redis重启时会通过执行保存的命令重建。

        优缺点:

        1.RDB:优点是只有一个文件,方便持久化,容灾性好,保证高性能(使用子进程持久化,主进程不进行I/O操作),数据集大的时候启动效率比AOF高;缺点是数据安全性低(因为RDB是间隔一段时间才会持久化)。

        2.AOF:优点是数据安全性高(因为AOF可以配置每进行一次就记录到AOF中,appendfsync属性设置为always),即使服务器宕机,也可以用工具(redis-check-aof)解决数据一致性问题。AOF没被rewrite前可以删除某些命令;缺点是文件比RDB大,恢复速度慢,数据集大时启动效率比RDB慢。

        注:两种同时启用,优先选择AOF。

9.描述IOC和AOP

        IOC和AOP是Spring拥有的两大特性,IOC是控制反转,AOP是面向切面。

        Spring的核心容器的主要组件是Bean工厂(BeanFactory),Bean工厂使用IOC模式来降低代码之间的耦合性,并提供了AOP的实现。

        通常我们实例化一个对象时,都是使用类的构造方法new一个对象,这个过程是由我们自己控制的,而IOC就是将创建对象的控制权交给了Spring容器;IOC可以使用依赖注入(DI)实现。

        DI就是容器全权负责把符合依赖关系的对象传递给需要的对象。通常使用注解注入,@Autowired和@Resource,两者的区别是前者可以自动装配,后者按照名称进行装配,名称通过name属性指定,没有指定name属性,当注解在字段、setter方法上时,默认去字段名、属性名装配。

        AOP提高了程序的可重用性,主要用于性能监视、日志记录、权限控制、事务管理等功能。AOP底层采用代理机制,分为JDK动态代理、CGLIB代理,前者由接口和实现类组成,后者没有接口,只有实现类。

        AOP的术语由target(目标类:需要被代理的类)、Joinpoint(连接点:程序执行的某个特定位置)、PointCut(切入点:已经被增强的方法)、Advice(增强、通知:在特定的连接点,执行的动作)、Aspect(切面:类似于Java中的类声明,包含一些PointCut、Advice)。

        AOP通知方式分为@Before(方法调用之前执行)、@After(方法返回或异常之后执行)、@AfterReturning(方法返回后执行)、@AfterThrowing(方法抛出异常后执行)、@Around(将方法封装起来)。

10.Spring MVC启动流程

        用户发送请求至前端控制器DispatcherServlet

        前端控制器收到请求调用处理器映射器HandlerMapping

        处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器,一并返回给前端控制器

        前端控制器调用处理器适配器HandlerAdapter

        处理器适配器经过适配调用具体的后端控制器Controller

        Controller执行完成返回ModelAndView

        处理器适配器将ModelAndView返回给前端控制器

        前端控制器将ModelAndView传给视图解析器ViewReslover

        视图解析器解析后返回具体View

        前端控制器根据View进行渲染视图

        前端控制器响应用户。

11.生成分布式ID的方式

        1.数据库自增序列:简单,但在读写分离、一主多从的情况下,因为只有一个主库可以生成,所以会有单点故障的危险;

        2.UUID:简单,性能好,能解决数据迁移、合并等问题,但是没有排序,往往是字符串,查询速率低,需要的存储空间大;

        3.Redis:单线程,可以使用Incr和IncrBy来实现,不需要依赖数据库,性能更佳,灵活性更强,可以排序,但是需要引入Redis组件;

        4.雪花算法:不依赖数据库,id按时间在单机上递增,但是涉及分布式环境,每台机器时钟不可能完全同步,会出现不是全局递增情况。

12.仿百度网盘的上传功能(个人项目,不予介绍)

13.介绍zk生成ID生成器(个人项目,不予介绍)

14.数据库中有1000w的数据,而Redis只有50w数据,如何保证redis中10w数据都是热点数据

       Redis有6中淘汰策略:noeviction不删除策略,达到最大内存限制时直接返回错误信息(默认淘汰策略);allkeys-lru:在所有key中优先删除最近最少使用的key;allkeys-random:在所有key中随机删除一部分key;volatile-lru:在设置了超时时间的key中优先删除最少使用的key;volatile-random:在设置了超时时间的key中随机删除一部分key;volatile-ttl:在设置了超时时间的key中优先删除剩余时间短的key。

        因此解决方法就是限定Redis占用的内存,Redis会根据自身数据淘汰策略,留下热数据到内存。计算50w数据大约需要占用的内存,然后设置Redis内存限制,将淘汰策略设置为volatile-lru或者allkeys-lru。设置最大占用内存:maxmemory;设置过期策略:maxmemory-policy。

15.如何加快MySQL处理速度 

        1.尽量避免where子句中使用!=;

        2.尽量避免where子句中对字段进行null值判断;

        3.尽量避免全表扫描;

        4.索引不能随意添加,索引可以提高select速度,但是降低了insert和update速度;

        5.尽可能使用varchar代替char,变长字段存储空间小,可以节省空间;

        6.避免返回大数据量;

        7.避免大事务操作,提高系统并发能力。

16.MySQL建表原则

        定长和变长分离;

        常用字段和不常用字段分离;

        使用冗余字段或冗余表:牺牲空间来换时间。

17.描述悲观锁

        悲观锁总是假设最坏的情况,每次拿数据都认为会被修改。

        悲观锁主要是共享锁(S锁)、排他锁(X锁),前者就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能写;后者就是不能与其他锁并存,例如一个事务获取了排他锁,其他事务都能不获取其他锁,包括共享锁和排他锁,但是获取排他锁可以对数据进行读取修改。

猜你喜欢

转载自blog.csdn.net/qq_44978143/article/details/121974901