高级Java工程师面试必备

JDK基础

  1. Java集合类数据库结构,HashMap ConcurrentHashMap HashMap扩容的实现方式。

  2. 熟悉并发包工具的使用,和实现原理。

CountDownLatch、Semaphore和CyclicBarrier
AtomicStampedReference
https://www.jianshu.com/p/bb5105303d85

  1. volatile关键字的作用。

  2. 线程安全的条件。

  3. 乐观锁 悲观锁 可重用锁 公平锁 非公平锁。ReentrantLock是如何实现可重复性的,synchronized实现原理,偏心锁的实现方式,轻量级锁,重量级锁。

  4. AQS实现原理 。

AQS是一个抽象类,内部定义了线程状态、同步现场队列、尝试获取工作线程、释放阻塞线程等模板方法,用户可以自定义tryAcquire()和tryRelease()方法实现对线程的控制,来定义线程安全组件。阻塞的线程会在同步队列进行自旋操作。

  1. Java8的新特性。

a. 接口中增加default方法的定义;
b. 新增Lambda表达式的支持;
c. 支持函数式接口编程(只有一个抽象方法定义的接口);
d. 支持Stream流式操作;
e. 新增Optional对空指针的处理;
f. 对时间处理的增强。

Java8中新增的LocalDate,LocalTime,LocalDateTime是不可变类,是线程安全的,对应JDBC中的类型为date,time,timestamp。原始的Date和SimpleDateFormat都是线程不安全的。

  1. JDK中rt.jar java.util.concurrent.ThreadPollExecutor和Executors解读。
线程池构造函数参数

通过Executors构建的几款线程池
  1. 线程池线程超限时4种处理策略。

AbortPolicy:直接抛弃,并抛出异常;
CallerRunsPolicy:使用调用者所在的线程运行任务;
DiscardOldestPolicy:丢弃任务队列中的最后一个任务,并执行当前任务;
DisCardPolicy:直接抛弃,不执行。
*也可以自己实现RejectedExceptionHandler自定义处理策略,如:任务持久化,记录日志等。


Executor实现原理
  1. JDK原子类是如何处理并发问题的?

原子类通过各CPU指令提供的CAS(compare and swarp)锁,保证比较和交换是同一个原子操作,通过volatile关键字修饰变量值,保证其他线程修改内存值,本线程副本的可见性,每次通过传入内存值,期望交换值调用native方法compareAndSwarp进行比较,如果内存值和副本不一致,则返回false,重新拉去最新的内存值进行重试,直到一致进行交换。

  1. Lock对比Synchonized的优缺点。

失去了隐士获取或释放锁的便捷性,但却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。

  1. 为什么重写equals方法,一定要重写hashcode方法?

首先要明确equals成功的4个必要性(自反性、对称性、传递性、一致性)。重写equals方法,即不在按照Object默认的对象比较方法进行对象比较,按照自己的方式实现。如果此时不进行hashcode的重写,当对象使用散列集合时,由于集合在put方法中使用了hashcode的来比较对象的相同性,即在比较前先验证对象hashcode是否相同,不相同则直接认为不是同一个对象。此时按照用户自定义的equals方法是同一个对象,而在使用集合时因为未重写hashcode方法导致对象重复问题等出现。

JVM

  1. 内存模型,各模块作用。

堆,虚拟机栈,程序计数器,方法区,常量池,本地方法区

  1. 垃圾回收算法。

标记清除,标记整理
关键词:minor gc full gc 引用计数法 可达性检测

  1. 强引用、软引用、弱引用、虚引用;弱引用在ThreadLocal的引用,为什么使用弱引用,ThreadLocal在使用时存在的问题,需要注意什么?使用不当存在内存泄漏的风险。
  2. 垃圾回收器有哪些?CMS,G1

CMS是作用于老年代,需要配合其他年轻代回收算法使用,存在初始标记、并发标记、重复标记、并发清除几个步骤。具有效率高/停顿时间短的特点,但是会存在产生内存碎片的问题,当老年代无法分配由年轻代进阶的整块内存时,会出发fullGC。当然可以通知JVM配置,定期对内存碎片进行整理。
G1是基于全堆的回收算法,把堆分成若干Region,使用标记整理和复制算法对内存回收、整理。实现步骤和CMS类似,但是只有并发标记阶段是并行的。

  1. 如何分析线上的OOM问题?

jps jstack jstat jhat jmap

  1. 类加载的过程,类加载器有哪些,什么是双亲委派模型?

启动类加载器,扩张类加载器,应用类加载器(系统类加载器),用户自定义类加载器 。
什么是双亲委派模型?双亲委派模型表示的启动类加载器、系统类加载器、应用程序类加载器、用户自定义类加载器之前的层级关系,除了启动类加载器外,都需要有自己父类加载器,并优先使用父类加载器,在父类加载器未找到对应类时,才会调用子类加载器加载。其中父子关系是基于组合复用来完成。
为什么要使用双亲委派模型:使Java类随加载器一样,保证优先级的层级关系,避免相同类限定名不同类的情况的出现。

  1. 类加载机制。

类的生命周期:加载—>验证—>准备—>解析—>初始化—>使用—>卸载 其中验证、准备、解析被称作连接阶段。
如何实现一个类加载器:继承java.lang.ClassLoader抽象类,实现loadClass方法。

数据库

  1. 数据库事务隔离级别(未提交、读已提交、可重复读、串行化),和脏读,不可重复读,幻读之间的关系。mysql在InnoDB下的默认隔离级别是可重复读
事务隔离级别

a.脏读: 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
b. 不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
c.幻读:第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

  1. mysql时如何实现事务的?实现原理。

  2. mysql有哪些锁,行级锁的作用对象是什么,生效条件?

InnoDB支持表级别锁和行级锁,行级锁加载单行数据,只有通过索引字段检索出的行才会加锁。

  1. 常用的SQL优化方案有哪些?

a.在连表查询的时候尽量用数据量小的表作为主表;提前缩小要查询数据的范围,提前分页;
b.选择合适的查询原语;
c.建立合适的索引,并使用之加快查询效率,必要时可以指定查询使用的索引FORCE INDEX(索引名称)。建立覆盖索引,减少回查次数;

  1. 数据库索引为什么有左偏性,什么是聚簇索引,什么是非聚簇索引?

  2. mysql数据库的myisam和innodb有什么区别?

InonDB和myIsam对比

Spring

  1. IoC原理。

是一种设计思想,将原本对象与对象的相互依赖转变成对象和容器的依赖,起到降低耦合的作用。由容器来管理对象的创建、实例化、依赖等工作。

  1. AOP原理,实现方式。
  2. 描述SpringMVC处理请求的内部实现。
SpringMVC实现原理
  1. IoC容器的功能,BeanFactory和ApplicationConttext的区别。

IoC解析配置加载,实例化Bean,并维护Bean之间的依赖关系,管理Bean的生命周期。
a. ApplicationContext集成自BeanFactory,是BeanFactory的加强版,在其基础上添加对,国际化支持,支持统一的资源文件读取方式;
b. ApplicationContext是在容器启动的时候将所有的Bean实例化,能更早的发现容器配置的错误,但是更加占用内存,启动更加耗时,BeanFactory采用延迟加载来注入Bean;
c. ApplicationContext和BeanFactory都支持BeanPostProcessor/BeanFactoryPostProcessor,不同的是前者自动注册,后者需要手动注册。

  1. Spring中bean的生命周期。

和Servlet的实例化instantiation、初始化init、接收请求service、销毁destroy。
a. 实例化Bean;
b. 设置属性;
c. 调用Aware方法;
setBeanNameAware();
setFactoryNameAware();
setApplicationNameAware();
d. 调用自定义的PostProcessor方法,进行前置处理;(传递Bean对象)
e. 调用InitializingBean的afterPropertiesSet和init-method,完成后续处理;(未传入Bean对象)
f. 使用Bean;
g. 销毁Bean,调用destroy-method方法

  1. spring bean scope。

singleton prototype request session global-session

  1. Spring是如何解决循环依赖的?

构造注入和prototype是无法解决循环依赖的。
a. bean创建中的对象放入缓存beanFactory中,在出现循环依赖时,直接从缓存中取出创建中的对象;
b. 完成属性填充。

  1. Spring中常见的设计模式。

工厂模式 : BeanFactory
装饰器模式: BeanWrapper
代理模式: AopProxy
单例模式: ApplicationContext
委派模式: DispatcherServlet
策略模式: HandlerMapping
适配器模式: HandlerApdapter
模板方法模式: JdbcTemplate
观察者模式: ContextLoaderListener

  1. springboot starter实现方式。

依赖spring-boot-autoconfigure/spring-boot-configuration-processor
a. jar包依赖
b. 创建properties,添加配置项目和默认配置
c. 创建configuration类加载properties
d. 创建factories文件,开启configoration

  1. SpringBoot2有哪些新特性?

a. 基于Java8/Java9;
b. 响应式编程,引入了Spring WebFlux ,WebFlux是一款非阻塞式的函数式编程框架,可以用来构建异步的、非阻塞式的、事件驱动的服务,具有更好的伸缩性。此框架来源于Spring5;
c. 开始支持HTTP2.0;
d. 支持 Quartz;
e. 简化了Secrity的安全配置;
f. 添加了对OAuth2的支持;
g. 数据库方面:HikariCP替换了tomcat-pool,提高了DB的访问速度,拥有更好的性能;redis默认引入Lettuce,替换了之前的jedis链接方式。

  1. Spring AOP的实现方式。

AOP:面向切面编程,是一种通过代理技术在程序编译期或运行期将外部代码编制到原代码中的编程模式,以降低程序耦合度,提高代码重用。
AOP的织入方式:i、编译期织入,如:AspectJ静态织入;ii、类装载时织入;iii、运行期织入,在运行期未目标类增强生产子类的方式,如SpringAOP;
SpringAOP动态代理技术:JDK动态代理,主要使用的是reflect包中的Proxy和InvovationHandler实现;CGLIB动态代理:CGLIB是一个高效的代码生成类库,使其在目标类不是接口的情况下依然可以实现代理。
SpringAOP实现策略:默认策略是在目标为接口时使用JDK动态代理,否则使用CGLIB实现;可以通过AopProxyFactory的AdvisedSupport对象配置。

微服务

  1. 分布式事务的实现策略。什么CAP原则和BASE理论?

CAP原则:指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
BASE理论:基本可用、软状态、最终一直性
什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。

  1. TX-LCN的事实现原理。
官网原理图

正常事务时序图

异常事务时序图
  1. 理解zk选举算法的实现原理。

  2. 分布式锁的实现方案,实现原理,redis是如何实现分布式锁的?

  3. 理解一致性哈希算法。

  4. SpringCloud几大组件。

注册中心:eureka
客户端负载均衡:ribbon
分布式配置中心:config
声明式服务调用:feign
服务容错保护:hystrix
API网管:zuul
消息总线:bus
hystrix原理:metrics存储了各服务状态、调用次数、调用失败次数。服务调用时,检测是否超时或失败,和设定的阈值次数、超时时间比较,确定服务是否需要熔断,是否需要打开熔断开关,并更新服务状态。当熔断器处于打开状态时,会按照设定的休眠时间,对熔断的服务作failback处理,休眠时间之后,会尝试请求服务,如果服务正常则关闭熔断器状态,以达到服务容灾的功能。
简述熔断器滑动窗口的实现方式;涉及的技术观察者模式和RxJava。

  1. rockerMQ 的优缺点,和其他消息中间件对比。

消息持久化为磁盘文件,支持分布式部署,高可用,理论不存在消息丢失情况出现。

  1. Redis相比memcached有哪些优势?

a. memcached所有的值均是简单的字符串,Redis作为其替代者,支持更为丰富的数据类型;
b. Redis的速度比memcached快很多;
c. Redis可以持久化其数据;
d. Redis支持数据的备份,即master-slave模式的数据备份;
e. Redission分布式锁的实现和原理。

  1. Redis线程模型。

  2. redis存在哪些问题,如何解决?

缓存数据库双写一致性问题;
缓存击穿
缓存雪崩
缓存key竞争问题

  1. RPC调用的原理。

1-客户端以本地接口的方式调用服务;
2-客户端存根接收到调用后,将方法、参数组装成可以网络传输的序列化的二进制消息体;
3-客户端通过socket将消息发送到服务端;
4-服务端存根收到消息体后进行解码(反序列化);
5-根据解码的消息体调用本地服务,得到结果后,由服务端存根进行序列化成消息体;
6-服务端通过socket将消息体发送给客户端;
7-客户端存根收到消息体后解码;
8-完成本地RPC调用。

  1. consul实现原理。

  2. erurka 的实现原理,和consul,zookeeper有什么区别?

  3. rocketMq事务型消息的实现原理。

事务消息的实现原理

数据结构和算法基础

  1. 理解二叉树、二叉搜索树(二叉排序树,二叉查找树)、平衡二叉树AVL、红黑树。

https://baijiahao.baidu.com/s?id=1636557496125304849&wfr=spider&for=pc&isFailFlag=1

  1. 排序算法:冒泡排序、快速排序、堆排序、插入排序、希尔排序实例方式,算法复杂度和空间复杂度。
常用排序算法的时间/空间复杂度
  1. BigMap在亿级数据的排序问题。

  2. 手写二叉树的前序、中序、后序遍历。

设计模式

  1. 设计模式的6大原则。

——开闭原则:对扩展开发,对修改关闭;
——里氏代换原则:所有能够使用基类的地方都可以使用子类代替;
——依赖倒转原则:依赖于抽象,不依赖于具体;
——接口隔离原则
——最少知道原则
——合成复用原则:尽量使用组合复用,少用继承。

  1. 单例模式实现方式:

饿汉方式:构建静态属性,在类加载的时候就进行初始化,线程安全;
双重检测方式;
静态内部类方式;
枚举方式。

package com.ljf.demo.singleton;

/**
 * 双重检查模式,最繁琐的一种方式
 */
public class DoubleClickSingleton {
    // 使用volatile关键字是为了禁用指令重排序,保证实例在线程间的可见性
    private volatile static DoubleClickSingleton instance;

    private DoubleClickSingleton() {
    }

    public static DoubleClickSingleton getInstance() {
        // 提高效率
        if (instance != null) {
            return instance;
        }

        synchronized (DoubleClickSingleton.class) {
            if (instance != null) {
                return instance;
            }

            return new DoubleClickSingleton();
        }
    }
}

package com.ljf.demo.singleton;

/**
 * 枚举就是一个典型的单例
 */
public enum EnumSingleton {
    INSTANCE("Hello World");

    private String name;

    EnumSingleton(String name) {
        this.name = name;
    }
}

package com.ljf.demo.singleton;

public class HungrySingleton {
    /**
     * 饿汉模式,在类加载的时候就进行实例化,线程安全
     */
    private static HungrySingleton instance = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return instance;
    }

}

package com.ljf.demo.singleton;

/**
 * 通过静态内部类实例化单例(目前最佳的实现方式)
 */
public class InnerSingleton {
    private InnerSingleton() {

    }

    public static InnerSingleton getInstance() {
        return Inner.instance;
    }

    private static class Inner {
        public static InnerSingleton instance = new InnerSingleton();
    }

    public static void main(String[] args) {
        InnerSingleton instance = InnerSingleton.getInstance();
        System.out.println("----------->");
    }
}

  1. 熟悉常见的设计模式的实现方式。

单例模式、代理模式、工厂模式、过滤器模式、观察者模式、模版方法模式、状态模式、策略模式、命令模式、责任链模式、建造者模式

场景分析

  1. 如何保证缓存和数据库数据的一致性?

设置缓存有效期;
先删除缓存,再修改数据库;
先更新数据库,再删除缓存,存在缓存建立中,缓存失效的问题,和缓存删除失败问题。

  1. 消息中间件如何保证消息投递、消费不丢失?从生产者、消费者分别分析。

  2. 描述浏览器输入网址到最终返回页面所经历的流程。

  1. DNS查询
  2. TCP连接
  3. 发送HTTP请求
  4. Server处理HTTP请求并返回HTTP报文
  5. 浏览器解析并render页面
  6. HTTP连接断开
  1. 如何让系统支持高可用、高平发?

a. 扩容服务;
b. 热点数据设置缓存(注意缓存击穿和血崩等问题,缓存一致性解决方案)
c. 增加浏览器缓存,使用CDN加速
d. 使用消息中间件异步处理和削峰处理
e. 流量限流处理
f. 服务拆分

  1. 服务拆封的原则。

降低耦合/提高复用/提高系统开发部署的效率/优化资源整合

其他

  1. junit 用法,before,beforeClass,after, afterClass 的执行顺序。

@BeforeClass -> @Before -> @Test -> @After -> @AfterClass

  1. Linux 文件系统中如何表示权限的?

r w x 分别表示可读 可写 可执行 对应数字1 2 4,通过数字之和表示文件对应的权限,文件权限共分为三组,左到右分别表示当前用户对该文件的权限,当前用户组用户组对应权限,所有用户对应权限。

你可能感兴趣的:(高级Java工程师面试必备)