java相关面试题

JVM相关知识:

什么是类的加载?
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的 Class对象, Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误
加载.class 文件的方式?
1.从本地系统中直接加载
2.通过网络下载.class文件
3.java源文件进行编译
等等…
谈谈类的生命周期?
类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始。
JVM类加载机制?
全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
类加载有三种方式?
1、命令行启动应用时候由JVM初始化加载
2、通过Class.forName()方法动态加载
3、通过ClassLoader.loadClass()方法动态加载.
Class.forName()和ClassLoader.loadClass()区别
Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
Class.forName(name,initialize,loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象 。
什么是双亲委派模型?
大致工作流程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
JVM内存结构?
JVM内存结构主要有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配;
方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。
控制参数
● -Xms设置堆的最小空间大小。
● -Xmx设置堆的最大空间大小。
● -XX:NewSize设置新生代最小空间大小。
● -XX:MaxNewSize设置新生代最大空间大小。
● -XX:PermSize设置永久代最小空间大小。
● -XX:MaxPermSize设置永久代最大空间大小。
● -Xss设置每个线程的堆栈大小。
没有直接设置老年代的参数,但是可以设置堆空间大小和新生代空间大小两个参数来间接控制
老年代空间大小=堆空间大小-年轻代大空间大小
什么是堆?
Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
什么是方法区?
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
什么是JVM栈?
Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
GC中对象存活判断?
引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。
可达性分析:(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。
在Java语言中,GC Roots包括:
● 虚拟机栈中引用的对象。
● 方法区中类静态属性实体引用的对象。
● 方法区中常量引用的对象。
● 本地方法栈中JNI引用的对象
GC垃圾收集有哪些算法?原理是什么?
**标记 -清除算法:**首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
**复制算法:**它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法的代价是将内存缩小为原来的一半,持续复制长生存期的对象则导致效率降低。
**标记-压缩算法:**让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存(将要回收的对象、存活的对象分别向两端移动)。
分代收集算法:在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。
有哪些垃圾收集器?
**Serial收集器:**串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩;垃圾收集的过程中会Stop The World(服务暂停)
**Parallel收集器:**Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;新生代复制算法、老年代标记-压缩
参数控制: -XX:+UseParallelGC 使用Parallel收集器+ 老年代串行
**CMS收集器:**CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
整个过程分为4个步骤,包括:
● 初始标记(CMS initial mark)
● 并发标记(CMS concurrent mark)
● 重新标记(CMS remark)
● 并发清除(CMS concurrent sweep)
初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。
优点: 并发收集、低停顿
缺点: 产生大量空间碎片、并发阶段会降低吞吐量
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)
G1收集器:
1.空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。
2.可预测停顿,这是G1的另一大优势,降低停顿时间是G1和CMS的共同关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。
JVM调优命令?
jps:JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
命令格式: jps [options] [hostid]
● -l : 输出主类全名或jar路径
● -q : 只输出LVMID
● -m : 输出JVM启动时传递给main()的参数
● -v : 输出JVM启动时显示指定的JVM参数
jstat:jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
命令格式: jstat [option] LVMID [interval] [count]
[option] : 操作参数
LVMID : 本地虚拟机进程ID
[interval] : 连续输出的时间间隔
[count] : 连续输出的次数
jmap:
jhat
jstack
jinfo

并发编程

你有使用过多线程吗?
多线程的作用是什么? 提高程执行效率
你们项目中那些地方使用到多线程?
批量异步导入数据,处理MQ大量消费数据
线程和进程的区别是什么?
进程–资源分配的最小单位,线程——程序执行的最小单位
Java实现线程有哪几种方式?
继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。
启动线程方法start()和run()有什么区别?
直接使用run,那就是执行一个普通的方法,start才是真正开启多线程。
怎么终止一个线程?如何优雅地终止线程?
使用volatile标志位
一个线程的生命周期有哪几种状态?它们之间如何流转的?
新建状态、 可运行状态、运行状态、阻塞状态(wait、sleep/join、synchronized)、死亡状态
在这里插入图片描述
谈谈线程安全问题?
对于可共享的资源变量,多个线程同时去操作的时候,会引发线程安全问题
你在项目中遇到过线程安全吗
线程之间如何实现同步呢: synchronized同步、ReentrantLock(重入锁)、ThreadLock、LinkedBlockingQueue、Atomic原子类
谈谈Java内存模型
线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。
多线程之间如何进行通信呢
wait()、 notif()、notifAll()
新建T1、T2、T3三个线程,如何保证它们按顺序执行? join方法
什么是死锁?如何避免死锁? 多个线程互相等待对方释放的资源从而出现了死锁,避免嵌套锁。
线程中的wait()和sleep()方法有什么区别?
sleep不释放锁,wait()释放锁。
什么是守护线程?有什么用?

ThreadLocal作用是 提高一个线程的局部变量,访问某个线程拥有自己局部变量。
ThreadLocal原理是 通过一个map集合 map.put(“当前线程”,值);
ThreadLocal内存泄露
ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。
每次使用完ThreadLocal,调用它的remove()方法,清除数据。
volatile与synchronized区别是什么?
volatile具有可见性,但不能保证原子性,但性能比synchronized高。
什么是重排序
编译器和处理器可能会对操作做重排序,即不一定会按照代码编写的顺序执行。
什么情况下,重排序对程序有影响。
多线程并发执行某块代码的情况下,会影响程序的执行结果,建议使用volatile、synchronized 防止重排序。
怎么保证线程可见性
使用volatile、synchronized关键字,或并发包中的原子类。
保证"可见性"有哪几种方式?

谈谈你对并发队列理解
有界队列与无界队列区别
非阻塞队列与阻塞队列的区别
你了解那些Jdk的并发包
线程池的有那些分类?
newCachedThreadPool(可缓存的)、newFixedThreadPool(定量的)、newSingleThreadExecutor(单个线程)、
newScheduledThreadPool(定时任务的)
为什么要使用线程池?
提高系统资源的利用率,提高程序的性能。
线程池实现原理
提交一个任务到线程池中,线程池的处理流程如下:
1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
线程池配置多少最合适
线程数量跟当前系统的CPU核数相关
线程池启动线程submit()和execute()方法有什么不同?
submit()返回线程执行的结果,execute()没有
提交任务时线程池队列已满会时发会生什么
阻塞,并放入到队列当中,当有空闲的线程的时候从队列里取。
什么是活锁、饥饿、无锁、死锁?
死锁:多个线程相互占用对方的资源的锁,而又相互等对方释放锁
活锁:多个线程相互主动释放资源给其他线程,导致资源不能得到执行。
饥饿:线程有优先级,优先级高线程的总是比优先级低的线程先执行,导致优先级低的无法得到执行
无锁:无锁典型的特点就是一个修改操作在一个循环内进行,线程会不断的尝试修改共享资源,如果没有冲突就修改成功并退出否则就会继续下一次循环尝试。
说几个常用的Lock接口实现锁。
Lock锁与synchronized区别式什么
lock需要手动释放锁。
CyclicBarrier和CountDownLatch的区别?

CountDownLatchCyclicBarrier
减计数方式加计数方式
计算为0时释放所有等待的线程计数达到指定值时释放所有等待线程
计数为0时,无法重置计数达到指定值时,计数置为0重新开始
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞
不可重复利用可重复利用

ThreadPoolExecutor有那些参数
corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、keepAliveTime(空闲超时时间)、workQueue(缓存任务的阻塞队列)
你了解那些锁?
CAS、偏向锁、重入锁、轻量级锁、重量级锁、乐观锁、悲观锁、自旋锁 等等。
什么是重入锁?
锁可以进行传递

乐观锁与悲观锁有那些区别

Fork/Join框架是干什么的?
将一个大的任务,拆分成若干个小任务去并发执行,最后把结果进行汇总。
实现原理:ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责将存放程序提交给ForkJoinPool,而ForkJoinWorkerThread负责执行这些任务。当我们调用ForkJoinTask的fork方法时,程序会把任务放在ForkJoinWorkerThread的pushTask的workQueue中,异步地执行这个任务,然后立即返回结果

你用过那些原子类?
AtomicInteger…
原子类的原理你有过了解吗?
采用CAS无锁,比较法。
怎么检测一个线程是否拥有锁?
java.lang.Thread类的holdsLock()方法
线程之间如何传递数据?

什么是CAS算法?在多线程中有哪些应用
一个CAS方法包含三个参数CAS(V,E,N)。V表示要更新的变量(主内存的值),E表示预期的值(本地内存),N表示新值。只有当V的值等于E时,才会将V的值修改为N。如果V的值不等于E,说明已经被其他线程修改了,当前线程可以放弃此操作,也可以再次尝试次操作直至修改成功。基于这样的算法,CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰(临界区值的修改),并进行恰当的处理。
什么是CAS无锁机制?
什么是自旋转锁
自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
但是线程自旋是需要消耗cup的,说白了就是让cup在做无用功,线程不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。
如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。
自旋锁与互斥锁区别
什么是Future模式?
得到将来的一个结果。
Callable与Therad区别
你了解那些并发框架
并发包
如果检测死锁?
Lock锁底层原理是什么?
你有了解过AQS吗?
AQS应用场景在那些地方
Synchronized底层实现原理?

框架源码分析

谈谈什么是Spring
为什么要用Spring
什么是SpringIOC容器
SpringIOC实现原理
什么是SpringAOP
面向切面编程,简单的说就是,在代码运行过程中能对其类下面的方法,在方法被调用之前、运行中、之后、异常。等做一些操作。
SpringAOP技术原理
通过代理设计模式。
AOP技术的应用场景
日志、事务、全局捕获异常、鉴权。等一些可以抽取的重复代码。
AOP技术底层实现原理
字节码技术
动态代理与静态代理区别
静态需要自己写代理类,动态通过jdk自带的、或者其他框架自动帮我们实现代理方法
CGLIB底层使用什么技术
字节码
Spring常用注解
Spring框架中的单例bean是线程安全的吗?
Spring使用ThreadLocal解决线程安全问题
Spring事务的分类
声明式、编程式
Spring事务传播行为
PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
Spring事务实现原理
AOP
使用Spring事务注意事项

Beanfactory与Factorybean
BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
Factorybean以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。
Spring生命周期
【Spring上下文的生命周期】

  1. 实例化一个Bean,也就是我们通常说的new
  2. 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入
  3. 如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID
  4. 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(),传递的是Spring工厂本身(可以用这个方法获取到其他Bean)
  5. 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文,该方式同样可以实现步骤4,但比4更好,以为ApplicationContext是BeanFactory的子接口,有更多的实现方法
  6. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术
  7. 如果这个Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法
  8. 如果这个Bean关联了BeanPostProcessor接口,将会调用postAfterInitialization(Object obj, String s)方法
    注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例
  9. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法
  10. 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法

Spring作用域
singleton、prototype、request、session、global session
SpringMVC执行流程

  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
  4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
    HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
  5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
  6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的 ViewResolver)返回给DispatcherServlet ;
  7. ViewResolver 结合Model和View,来渲染视图
  8. 将渲染结果返回给客户端。
    Mybatis接口与SQL语句绑定的原理

集合框架中用到了那些数据结构
数组、链表、二叉树 等。
Arraylist底层实现原理
数组的复制算法
Arraylist的Add方法实现原理
1.当新增的元素,在容量范围内,会往当前数组后面追加元素,也是通过数组copy,去替换之前的数组。
2.当新增一个元素需要在指定的位置添加元素时,会先将当前插入的位置下标与当前数组最后的一个元素下标,都往后进行位移一个单位,得到新的数组去覆盖之前旧的数组并返回。

Arraylist的Get方法实现原理
数组的下标
Arraylist扩容机制原理
判断当前新增的元素是否会超过当前容量,超过就进行扩容,扩容大小=原有容量的1.5倍+1
Arraylist底层数组默认初始化多少
10
Vector与Arraylist区别
Vector的方法都加了synchronized,所以线程安全
LinkedList底层实现原理
双向链表
LinkedList的Add方法实现原理
改变要添加元素的节点指针。
LinkedList的Get方法实现原理
每一个节点包含了上一个节点和下一个节点信息,查找某一个节点,都是通过 next属性,一个一个往下找。
LinkedList与Arraylist区别
Arraylist 底层通过一个数组实现的,所以查询快,新增修改都是通过数组的copy来实现,每次新生成的数组会覆盖之前旧的数组,所以比较慢。
LinkedList底层是通过一个双向链表实现的,没个节点都保存了上一个节点和下一个节点的信息。
在新增、修改等操作,直接修改当前节点的上一个指针、下一个指针。但是查询就比较慢了,因为,查询是一个一个节点往下找,知道找到为止。

Set集合接口实现原理
HashSet的底层结构是哈希表(实际上是一个HashMap实例)。HashSet集合是通过元素中继承自Object超类的hashCode()方法和equal()方法来判断两个对象是否相同的。
HashMap实现原理
数组+链表来实现。
HashMap的Put方法实现原理
int index=key.hashCode()%tables.length;
put的时候,拿到key的hashCode()值,然后对当前数组长度进行取模,得到当前key应该对应在数组的哪个下标位置。然后就值放入到这个数组当中。(数组里存放的是一个单向链表)
HashMap的Get方法实现原理
同put一样,得到当前值存放在哪个数组下标位置。然后得到数组里的值,并返回。
HashMapHash碰撞问题如何解决的?
其实这个应该叫数组下标冲突。因为key的hashCode%当前数组长度 的时候,会存在多个key得到下标都是相同的,那么在添加的时候就会出现新的值会覆盖旧的值。所以hashmap的每个下标数组中存放了一个单向列表,这链表里存储的数据都是index相同的元素。
HashMap1.7实现与1.8实现的区别
1.7: 数组+链表
1.8: 数组+链表/红黑树
HashMap负载因子的作用是什么
而负载因子表示一个散列表的空间的使用程度,有这样一个公式:initailCapacityloadFactor=HashMap的容量。
所以负载因子越大则散列表的装填程度越高,也就是能容纳更多的元素,元素多了,链表大了,所以此时索引效率就会降低。
反之,负载因子越小则链表中的数据量就越稀疏,此时会对空间造成烂费,但是此时索引效率高。
HashMap底层扩容机制实现原理
当HashMap的长度超出了加载因子与当前容量的乘积(默认16
0.75=12)时,通过调用resize方法重新创建一个原来HashMap大小的两倍的newTable数组,最大扩容到2^30+1,并将原先table的元素全部移到newTable里面,重新计算hash,然后再重新根据hash分配位置。这个过程叫作rehash,因为它调用hash方法找到新的bucket位置
Hashcode和Equals区别

为什么HashTable的默认大小和HashMap不一样

SpringBoot 相关
什么是SpringBoot
为什么要用SpringBoot
SpringBoot启动方式
SpringBoot与SpringMVC 区别
SpringBoot与SpringCloud 区别
SpringBoot中用那些注解
@EnableAutoConfiguration作用
开启配置
@SpringBootApplication原理

SpringBoot热部署使用什么?
devtools
热部署原理是什么?
类加载
热部署原理与热加载区别是什么
你们项目中异常是如何处理
全局捕获异常
SpringBoot如何实现异步执行
@ASync注解
SpringBoot多数据源拆分的思路
分包存放、AOP+自定义注解
SpringBoot多数据源事务如何管理
SpringBoot如何实现打包
SpringBoot性能如何优化
SpringBoot2.0新特性
SpringBoot执行流程
springApplication.run()->initialize()
1.判断是否为Web应用,并使用webEnvironment标记是否为web应用
2.使用SpringFactoriesLoader在classpath中的spring.factories文件中查找并加载所有可用
ApplicationContexInitalizer

SpringBoot底层实现原理
基于SpringMVC无配置文件(纯Java)完全注解化+内置tomcat-embed-core实现SpringBoot框架,Main函数启动。
SpringBoot装配Bean的原理

Nginx 高可用相关面试题
什么是DNS解析域名
什么是Nginx
Nginx的作用
Nginx 应用场景
反向代理、服务限流、网关 等等
什么是反向代理
对外隐藏真实服务器的IP地址,外网访问nginx转发到真实的项目服务器地址
反向代理的作用
反向代理的好处隐藏真实内部ip地址,请求先访问nginx代理服务器(外网可以访问到),在使用nginx服务器转发到真实服务器中。
Nginx如何配置反向代理
conf文件下,server->location 节点设置
说说常用Nginx的相关配置
server、upstream
请画图展示反向代理流程

LVS与Nginx区别
四层负载均衡,在网络模型中的传输层中,基于主要是基于tcp协议报文实现负载均衡(比如LVS、haproxy就是四层负载均衡器),使用改写报文的源地址和目的地址。
location的作用
指向真实的项目路径
Nginx中如何配置负载均衡
四层负载均衡与七层负载均衡区别
四层负载均衡,在网络模型中的传输层中,基于主要是基于tcp协议报文实现负载均衡(比如LVS、haproxy就是四层负载均衡器),使用改写报文的源地址和目的地址。
七层负载均衡,在网络模型中应用层中,基于URL或者HTTP协议实现负载均衡,Web服务器。
四层负载均衡有那些实现方案
负载均衡有那些算法
服务器集群后,会产生了那些问题?
session
什么是动态负载均衡
Nginx如何实现动态负载均衡

什么是Http协议
Http协议组成部分
TCP与UDP区别
TCP:
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证  
UDP:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高
谈谈七层网络模型

lvs与keepalived区别
keepalived 作用
LVS可以实现负载均衡,但是不能够进行健康检查,比如一个rs出现故障,LVS 仍然会把请求转发给故障的rs服务器,这样就会导致请求的无效性。keepalive 软件可以进行健康检查,而且能同时实现 LVS 的高可用性,解决 LVS 单点故障的问题,其实 keepalive 就是为 LVS 而生的。
如何实现双机主从热备
lvs+Keepalived+Nginx架构流程图
项目发布如何不影响到正常用户访问,实现7*24小时访问
项目如何发生故障宕机了,如何处理。

动态网站与静态网站区别
动态页面静态化的作用
什么是动静分离架构模式
如何搭建动静分离
动静分离与前后分离区别
如何控制浏览器静态资源缓存
Http状态码304的作用

谈谈服务雪崩效应
分布式微服务高并发情况下,某个服务出现不可用的时候,会导致其他依赖的服务都会出现不可用。
在微服务中,如何保护服务
使用Hystrix实现服务降级
谈谈你的Hystrix理解
Hystrix 是一个微服务关于服务保护的框架,是Netflix开源的一款针对分布式系统的延迟和容错解决框架,目的是用来隔离分布式服务故障。它提供线程和信号量隔离,以减少不同服务之间资源竞争带来的相互影响;提供优雅降级机制;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,并能从中快速恢复。Hystrix通过这些机制来阻止级联失败并保证系统弹性、可用。
服务隔离、降级、熔断、限流分别表达什么意思
隔离:
1.线程池隔离机制: 当大多数人在使用Tomcat时,多个HTTP服务会共享一个线程池,假设其中一个HTTP服务访问的数据库响应非常慢,这将造成服务响应时间延迟增加,大多数线程阻塞等待数据响应返回,导致整个Tomcat线程池都被该服务占用,甚至拖垮整个Tomcat。因此,如果我们能把不同HTTP服务隔离到不同的线程池,则某个HTTP服务的线程池满了也不会对其他服务造成灾难性故障。这就需要线程隔离或者信号量隔离来实现了。
使用线程隔离或信号隔离的目的是为不同的服务分配一定的资源,当自己的资源用完,直接返回失败而不是占用别人的资源。
2.信号量机制:
使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数 器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返 回成功后计数器-1。
与线程池隔离最大不同在于执行依赖代码的线程依然是请求线程
tips:信号量的大小可以动态调整, 线程池大小不可以
区别:
线程池隔离:
1、 第三方应用或者接口
2、 并发量大
信号量隔离:
1、 内部应用或者中间件(redis)
2、 并发需求不大
降级:服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
熔断:如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用
服务限流:限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。
服务隔离有几种实现方式
线程池隔离、信号量隔离
服务隔离线程池方式实现原理
对每个服务设定一个线程池,彼此不受干扰,因为出现并发情况的时候,多个请求处理不过来,那么就会放在队列里。这个时候就会有很多请求处于等待状态。
如何解决服务雪崩效应
Hystrix可以单独集成在项目中吗?

高并发服务限流特技有哪些算法?
高并发限流解决方案限流算法(令牌桶、漏桶、计数器)、应用层解决限流(Nginx)
传统计数器限流算法有什么弊端?
什么是滑动窗口计数器

令牌桶算法的原理
令牌桶算法是一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌。每次来一个请求,从桶里取,取不到就走服务降级策略
漏桶算法的原理
令牌桶与漏桶算法的区别

Web前端有哪些优化方案
什么是CDN内容分发
CDN内容加速原理
阿里云配置CDN内容分发步骤

互联网安全架构平台设计
如何设计一套互联网安全架构平台(暂时先不做,上完在做)
Web前端有哪些攻击手段?
什么是XSS脚本攻击
XSS攻击的原理?
XSS攻击的应用场景
如何防御XSS攻击
SQL注入的原理
防御SQL注入的原理
Mybatis#与$区别

防盗链技术实现原理
谈谈黑名单与白名单
http referer字段实现原理
什么是CSRF攻击
如何保证API接口幂等性
如何防止模拟请求
如何防止机器模拟请求
如果防止使用伪造Token模拟请求
如何保证互联网API接口幂等性
基于Token方式保证API接口幂等性流程
互联网API开放平台安全设计概述
OAuth2.0协议认证流程
信息加密有那些方案
接口为什么要加密传输
Java中如何URL特殊字符转码
什么是对称加密?有那些对称加密方式?优缺点是?
移动App接口安全设计有那些方案
非对称加密整个过程
如何防止抓包篡改数据
如何抓包分析Http请求,有那些工具
重定向底层实现原理
什么是Https协议
Https协议与Http协议之间的区别
Https协议请求整个原理过程
项目如何配置Https协议

常用有那些缓存框架?
本地缓存与分布式缓存区别?
如何解决缓存不同步的问题
Redis支持事务吗?
为什么要用Redis
Redis的应用场景
Redis的有那些数据类型
Redis缓存与DB不同步问题如何解决
Redis集群是否支持事务?
Redis主从复制的作用
Redis持久化机制有那些
Redis哨兵机制
RedisCluster集群原理
什么是缓存雪崩
缓存雪崩如何解决
什么是缓存穿透
缓存穿透如何解决
你们项目中有用到一级和二级缓存吗?为什么要这样设计

Zookeeper分布式协调工具:
什么Zookeeper?
Zookeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以单机模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。
1、zookeeper是为别的分布式程序服务的
2、Zookeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务)
3、Zookeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统> 一名称服务等
4、虽然说可以提供各种服务,但是zookeeper在底层其实只提供了两个功能:
管理(存储,读取)用户程序提交的数据(类似namenode中存放的metadata);
并为用户程序提供数据节点监听服务;
Zookeeper集群机制?
Zookeeper集群的角色: Leader 和 follower
只要集群中有半数以上节点存活,集群就能提供服务
Zookeeper特性
1、Zookeeper:一个leader,多个follower组成的集群
2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
3、分布式读写,更新请求转发,由leader实施
4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
5、数据更新原子性,一次数据更新要么成功,要么失败
6、实时性,在一定时间范围内,client能读到最新数据
ZK节点类型?
临时节点(客户端与ZK连接一断开就自动删除节点)、持久节点
ZK中,watcher是用来干嘛的?
在ZooKeeper中,接口类Watcher用于表示一个标准的事件处理器,其定义了事件通知相关的逻辑,包含KeeperState和EventType两个枚举类,分别代表了通知状态和事件类型,同时定义了事件的回调方法:process(WatchedEvent event)。
KeeperState EventType 触发条件 说明
None(-1) 客户端与服务端成功建立连接
SyncConnected(0) NodeCreated(1) Watcher监听的对应数据节点被创建
NodeDeleted(2) Watcher监听的对应数据节点被删除 此时客户端和服务器处于连接状态
NodeDataChanged(3) Watcher监听的对应数据节点的数据内容发生变更
NodeChildChanged(4) Wather监听的对应数据节点的子节点列表发生变更
Disconnected(0) None(-1) 客户端与ZooKeeper服务器断开连接 此时客户端和服务器处于断开连接状态
Expired(-112) Node(-1) 会话超时 此时客户端会话失效,通常同时也会受到SessionExpiredException异常
AuthFailed(4) None(-1) 通常有两种情况,1:使用错误的schema进行权限检查 2:SASL权限检查失败 通常同时也会收到AuthFailedException异常
Zookeeper应用场景?
数据发布订阅
负载均衡
命名服务
分布式协调
集群管理
配置管理
分布式队列
分布式锁
分布式锁解决思路
分布式锁使用zk,在zk上创建一个临时节点(有效期) ,使用临时节点作为锁,因为节点不允许重复。
如果能创建节点成功,生成订单号,如果创建节点失败,等待。临时节点zk关闭,释放锁,其他节点就可以重新生成订单号。

消息中间件MQ(记录一些比较重要的知识点):
什么是消息模型?
Point-to-Point(P2P) — 点对点
Publish/Subscribe(Pub/Sub)— 发布订阅
JMS消息可靠机制
ActiveMQ消息签收机制:
客戶端成功接收一条消息的标志是一条消息被签收,成功应答。
消息的签收情形分两种:
1、带事务的session
如果session带有事务,并且事务成功提交,则消息被自动签收。如果事务回滚,则消息会被再次传送。
2、不带事务的session
不带事务的session的签收方式,取决于session的配置。
Activemq支持一下三种模式:
Session.AUTO_ACKNOWLEDGE 消息自动签收
Session.CLIENT_ACKNOWLEDGE 客戶端调用acknowledge方法手动签收
textMessage.acknowledge();//手动签收
Session.DUPS_OK_ACKNOWLEDGE 不是必须签收,消息可能会重复发送。在第二次重新传送消息的时候,消息
只有在被确认之后,才认为已经被成功地消费了。消息的成功消费通常包含三个阶段:客户接收消息、客户处理消息和消息被确认。 在事务性会话中,当一个事务被提交的时候,确认自动发生。在非事务性会话中,消息何时被确认取决于创建会话时的应答模式(acknowledgement mode)。该参数有以下三个可选值:
Number Of Consumers 消费者 这个是消费者端的消费者数量

Number Of Pending Messages 等待消费的消息 这个是当前未出队列的数量。可以理解为总接收数-总出队列数
Messages Enqueued 进入队列的消息 进入队列的总数量,包括出队列的。 这个数量只增不减
Messages Dequeued 出了队列的消息 可以理解为是消费这消费掉的数量
ActiveMQ服务器宕机怎么办?
尽量不要用非持久化消息,非要用的话,将临时文件限制尽可能的调大
丢消息怎么办?
用持久化消息,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了
消息的不均匀消费?
原因:ActiveMQ的prefetch机制。当消费者去获取消息时,不会一条一条去获取,而是一次性获取一批,默认是1000条。
将prefetch设为1,每次处理1条消息,处理完再去取,这样也慢不了多少。
死信队列?
在重试6次后,ActiveMQ认为这条消息是“有毒”的,将会把消息丢到死信队列里。如果你的消息不见了,去ActiveMQ.DLQ里找找,说不定就躺在那里。
Activemq保证消息唯一?
通过MsgId
RockeMq部分知识
rocketMq有哪些组件,分别是干嘛的?
NameServer:单点,供Producer和Consumer获取Broker地址
Producer:产生并发送消息
Consumer:接受并消费消息
Broker:消息暂存,消息转发
RocketMQ如何解决消息幂等?
使用msg.setKeys 进行区分
rocketmq怎么保证队列完全顺序消费?
把订单号做了一个取模运算再丢到selector中,selector保证同一个模的都会投递到同一条queue。如果是使用MessageListenerOrderly则自带此实现,如果是使用MessageListenerConcurrently,则需要把线程池改为单线程模式。

CAP定理分布式事务:
ACID
● Atomicity(原子性):一个事务中所有操作都必须全部完成,要么全部不完成。
● Consistency(一致性): 在事务开始或结束时,数据库应该在一致状态。
● Isolation(隔离性): 事务将假定只有它自己在操作数据库,彼此不知晓。
● Durability(持久性): 一旦事务完成,就不能返回。
2PC (Two Phase Commitment Protocol) 二阶段提交
● 准备阶段
1)协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。
2)参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)
3)各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。
● 提交阶段
在这里插入图片描述
1)协调者节点向所有参与者节点发出”正式提交(commit)”的请求。
2)参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
3)参与者节点向协调者节点发送”完成”消息。
4)协调者节点受到所有参与者节点反馈的”完成”消息后,完成事务。
在这里插入图片描述
1)协调者节点向所有参与者节点发出”正式提交(commit)”的请求。
2)参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
3)参与者节点向协调者节点发送”完成”消息。
4)协调者节点受到所有参与者节点反馈的”完成”消息后,完成事务。
存在的问题:
1)同步阻塞问题。所有参与节点都是事务阻塞型的(换句话说,1个节点不处理完,其它节点就得等着,性能低下)
2)单点故障。一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态。
3)数据不一致。协调者向某个参与者发送commit请求之后,如果局部网络故障,会导致只有一部分参与者接受到了commit请求。于是整个分布式系统便出现了数据不一致性的现象。
4)事务状态可能不确定。协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,无法确实是否已提交(有点类似:薛定谔的猫)。
3PC/Paxos
2PC的改进- 3PC
一致性算法的终节者: Paxos (Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品。)
CAP定理
● Consistency(一致性), 即:1个节点的数据更新,能实时同步到其它所有节点
● Availability(可用性), 即:所有节点都不挂
● Partition tolerance(分区容错性) 即:绝对可靠,网络有抖动甚至故障也不受影响
定理:任何分布式系统只可同时满足二点,没法三者兼顾。
反证法可以很容易证明:
网络分区一定存在,无法回避(即:网络抖动或故障是必然存在的),P的存在(即:从1个节点到另1个节点的通讯,必然存在丢包的可能性)无法绝对保证2个节点之间的数据一致性,即满足P,就无法满足C。
反过来也类似,如果从A节点(master)到B节点(slave)的数据传输,由于P的存在,必然存在delay(延时),如果要想保证数据一致性,只能强制读取Master节点,这样B节点其实相当于不可用(即:永远用不到,丧失了可用性),同时Master也存在单点故障,A无法永远保证。
BASE原则
● Basically Available 基本可用 (即:允许部分节点失效,但是不至于整体全挂)
● Soft state 软状态 (即:各节点的状态,允许有一段时间不同步)
● Eventually consistent 最终一致 (即:最终数据能达到一致就行,而不是每时每刻都要绝对一致)
柔性事务(TCC: Try-Comfirm-Cancel)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值