java后台面试题整理(包含)

原创
2019/05/19 14:06
阅读数 179

java基础

1.Arrays.sort实现原理和Collection实现原理

Collection.sort()底层会调用Arrays.sort(),Arrays.sort()底层实现是TimeSort,TimeSort的算法就是先找到已经排好序数据的子序列,然后对剩余部分数据进行排序,然后在合并起来。

2.foreach和while的区别(编译之后)

while会读一行输入,把它存入某个变量并执行循环体,然后再找其他行的输入,适用于不确定循环次数的情况;foreach是增强for循环,它是逐条读取,在循环开始前会将所有输入全部读入,适用于数组、集合等确定长度的情况;当输入内容非常大的时候foreach会非常占内存。

3.线程池的种类,区别和使用场景

a.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

b.newFixedThreadPool创建一个定长线程池,可控制线程的最大并发数,超出的线程会进入阻塞队列中等待。

c.newScheduledTreadPool创建一个定长线程池,支持定时或者周期性任务执行。

d.newSingleThreadPool创建一个单线程化的线程池,它只会用唯一的线程来执行任务,保证所有任务按照指定顺序执行。

4.线程的调度过程 

a.当线程池小于corePoolSize时,新提交的任务会创建一个新的线程执行,技术此线程池中有空闲线程;

b.当线程池达到corePoolSize时,新提交的任务将被放入workQueue,等待线程池中任务调度执行;

c.当workQueue已满,并且maximunPoolSize > corePoolSize时,新提交的任务会创建新的线程执行;

d.当提交的任务数超过maximunPoolSize时,新提交的任务将被拒绝;

e.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程;

f.当线程池中设置allowCoreThreadTimeOut=true时,线程池中corePoolSize线程超过keepAliveTime时也将被关闭;

5.动态代理的几种方式

jdk动态代理和cglib动态代理。jdk动态代理是有java内部的反射机制实现的,前提是代理类和目标类必须实现统一的接口;cglib动态代理是借助asm来实现的。

6.HashMap的并发问题

HashMap是线程不安全的,当size超过一定大小需要扩容时,会重新计算hashcode值,在多线程的情况下可能会产生死循环。可以使用HashTable和ConcurrentHashMap。

7.HashTable和ConcurrentHashMap区别

当HashTable增加到一定数量时性能会急剧降低,因为迭代时会锁很长时间,而ConcurrentHashMap使用了分割,无论数量多大,都只需要锁map的某一个部分。

8.反射的原理,反射创建类实例的三种方式是什么

java反射机制实在运行当中,对任意一个类来说,能够知道它的所有属性和方法,都能调用它的任意一个属性和方法。

三种方式:getClass()方式,调用类的静态属性class,Class.forName()。

9.hashmap的理解

hashmap是链表+数组的存储结构,外层是一个链表,而每个链表中又是一个数组,存储时先通过key获取hashcode并计算出value存储的链表位置,如果不存在hash碰撞则value存在该链表中数组的第一个位置,如果发生hash碰撞则存在该链表的数组的最后一个位置。

10.arraylist和linkedlist区别及实现原理

arraylist是基于动态数组的数据结构,而linkedlist是基于链表的数据结构;对于查询来说arraylist优于linkedlist,而对于删除和新增则linkedlist更好些。

11.反射中,Class.forName和ClassLoader区别

java类加载的过程包括:加载->验证->准备->解析->初始化->使用->卸载,而初始化就是激活java类中静态变量初始化代码和静态代码块,并初始化程序设置的变量值。

Class.forName会执行类的初始化,而ClassLoader不会执行类的初始化。

JVM相关

1.jvm的理解:

java虚拟机内存分5个部分,程序计数器、java虚拟机栈、本地方法栈、堆、方法区。

程序计数器记录当前代码执行位置,进行代码流程控制,多线程时记录当前线程执行的位置,从而记录线程返回时上一次执行到哪了,程序计数器是一个很小的内存空间,每个线程都有一个程序计数器,随着线程的启动而创建线程的结束而消亡,不会出现OutOfMemoryError。

java虚拟机栈,java虚拟机会为每一个即将运行的方法分配一个叫“栈帧”的区域,记录该方法执行过程中所需要记录的信息(局部变量表、操作数栈、动态链接,方法出口等信息),方法运行时需要创建的局部变量被存放在局部变量表中,当方法执行完后这个这个方法所对应的栈帧将会出栈,释放空间,java虚拟机栈也是随着线程的创建而创建,线程的结束而释放,会出现2中异常:StackOverFlowError和OutOfMemoryError

本地方法栈和java虚拟机栈类似,只不过是用来运行本地方法的内存模型。

堆是用来存放对象的内存空降,几乎所有的对象都存放在堆中,java中堆时内存共享的随着虚拟机的启动而创建,堆是垃圾回收的主要场所,又可以分为新生代和老年代,堆的大小是可以扩展的,但也会抛出OutOfMemoryError。

方法区是堆的一个逻辑部分,存放着已经被虚拟机加载的类的信息、常量、静态变量、编辑后的代码等,方法区是内存共享的,整个虚拟机只有一个方法区,可以看做是堆的老年代,这里回收效率比较低,主要回收目标是对常量池的回收和类型的卸载。

2.java类创建的过程

当虚拟机遇到一个new指令时,检查常量池中是否有该对象所属类的符号引用,如果没有则抛出ClassNotFoundExecption异常,如果有,则检查这个符号所代表的类是否已经被jvm加载,如果没有被加载,则找到该类的class文件并加载进方法区,如果已经加载,则根据方法区信息为该对象在堆中分配一块内存空间指给新的对象。

3.如何判断哪些对象需要回收

引用计数法:每个对象都有一个计数器,当这个对象被引用时计数器加1,不被引用时减1,当这个计数器为0时则认为这个对象时无效对象。

可达性分析法:所有和gc roots(java虚拟机栈所引用的对象、方法区中静态属性和常量应用的对象、本地方法栈所引用的对象)有直接或间接关系的对象认为是有效对象,和gc roots没有关系的对象认为是无效对象。

4.java类实例创建的过程

先父类后子类;父类静态-子类静态-父类初始化块-父类构造方法-子类初始化块-子类构造方法。

5.synchronized与lock的区别

synchronized在同步块执行完成或者发生异常时释放锁,lock必须在finally中释放锁,不然容易死锁;synchronized假如线程A获得锁,线程B线程等待,如果线程A阻塞,则线程B一直等待lock有多种获取锁的方法,B可以不用等待尝试去获取锁;synchronized锁是非公平的,lock可以公平也可以非公平;synchronized适用于少量的代码同步,lock适用于大量的代码同步。

spring

1.Spring AOP与IOC的实现原理

ioc是spring最核心的内容,控制反转,也叫依赖注入,让一个对象的创建不需要new就能产生,实际上是通过反射机制,在对象调用的时候动态的创建和调用某个对象和方法;注入的方法有set注入,构造器注入和基于注解的注入。

aop也是spring的一大特色,aop通过动态代理实现了切面编程,可以用于对某个类的监督和管理,从而达到了一个模块扩充的功能。

spring的的目的就是让对象与对象之间的关系变成xml配置,从而实现了对象之间的解耦,spring就是一个容器,只有在容器中的对象才能提供这些功能和服务。

2.BeanFactory和FactoryBean的区别

BeanFactory是ioc的核心接口,用来创建和管理bean,它为其他ioc容器提供了最基本的规范,FactoryBean是ioc容器中为bean的实现提供了更加灵活的方式,FactoryBean在ioc容器中是给bean加了一个工厂模式和装饰模式。

3.为什么CGlib方式可以对接口的实现进行代理

cglib采用了非常底层的字节码技术,通过字节码为一个类创建子类,并在子类中采用方法拦截的方式拦截所有父类的调用顺势植入横切逻辑,所以传入接口就能实现。

分布式相关

1.Dubbo的底层实现原理和机制

client调用一个远程接口,生成一个唯一id,打包调用信息(接口、方法、参数)、和结果返回对象callback,将其封装成一个object,向专门的调用信息concurrentHashMap中put(id,object),然后将id和object封装成一个conRequest,使用IOSession.write(conRequest)异步发送请求,然后当前线程在试图使用callback的get()方法获取返回值,在get方法内部使用synchronized获取callback锁,如果获取不到结果则调用callback的wait()方法,释放callback锁并使线程处于等待状态,服务端处理后将结果返回给客户端,客户端的socket专门监听消息的线程接收到消息,分析结果取到id,从concurrentHashMap中获取object中的callback,将结果设置到callback中,监听线程在用synchronized获取callback锁,在notifyAll()唤醒当前处于等待的线程。

2.分布式系统怎么做服务治理

服务降级、服务流控、服务动态扩展、超时控制、优先级调度、负载均衡策略调整、分组调整、等。

3.对分布式事务的理解

消息事物+最终一致性

tcc编程模式

4.如何实现负载均衡,有哪些算法可以实现

轮询法、随机法、源地址Hash法、加权轮询法、加权随机法、最小链接数法

Redis&缓存相关

1.Redis的并发竞争问题如何解决

使用redis自带的incr命令

使用独占锁方式

程序加锁

利用redis的setnx实现内置的锁

2.Redis持久化的几种方式,优缺点是什么,怎么实现的

RDB存入缓存快照、AOF存入redis执行命令

3.Redis的缓存失效策略

redis在get时判断是否过期,如果过期则删除,同事redis会定时删除过期的key。

4.缓存穿透的解决办法

即使查询出来的值为null也存入一个默认的值,可以加上一个很短的过期时间

给缓存的key上加一个规则,如果不合法的key,则直接过滤掉

采用布隆过滤器

四、总结

在此我向大家推荐一个java互联网架构学习交流群。交流学习Q群号:1025177716 加群获得以上学习视频,群里面还会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部