JAVA面试题及答案整理

java多线程

线程池的原理,为什么要创建线程池?

1)线程池可以降低创建和销毁线程时的资源消耗,提高响应速度,提高线程的可管理性。

2)线程池构造参数:

corePoolSize:核心线程数

maximumPoolSize:最大线程数

keepAliveTime:空闲时间

unit:空闲时间单位

workQueue:任务等待队列。ArrayBlockingQueue(有界);SynchronousQueue(容量为1);LinkedBlockingQueue(无界)

threadFactory:线程工厂

handler:任务拒绝策略。丢弃并抛异常(默认策略);丢弃但不抛异常;丢弃最前面的任务;由调用线程处理该任务

1、几个参数之间的关系。

corePoolSize<=maximumPoolSize,线程池处理流程。

2、线程的生命周期,什么时候会出现僵死进程;

1)new -> runnable -> running -> block -> dead

2)两个线程相互等待对方释放锁时,会出现僵死现象

3、什么是现线程安全,如何实现线程安全;

1)多线程并发访问共享资源时,能保证结果正确

2)可通过阻塞同步(加锁);非阻塞同步(CAS);避免共享资源(session、threadLocal)

4、java线程池如何合理配置核心线程数?

1)获取CPU核数。Runtime.getRuntime().availableProcessors()

2)分析程序属于CPU密集型还是IO密集型?

CPU密集型,核心线程数=CPU核数+1。减少花在任务切换上的时间

IO密集型,核心线程数=CPU核心数*2。线程越多,CPU利用率越高

5、synchronized、volatile区别、synchronized锁粒度、模拟死锁场景、原子性与可见性; 

1)死锁产生的条件:互斥条件;环路等待;保持条件;不剥夺条件

2)synchronized锁粒度:无锁、偏向锁、轻量锁、重量锁

6、synchronized的实现原理是什么?
使用对象监控器来控制锁的实现,代码包含在monitorenter 和monitorexit 之间,执行monitorenter 对进入数加1,执行monitorexit 对进入数减1,其他线程在访问时进入数不为0,不能进入,如果进入数为0,获取锁。
同步锁在这种实现方式中,因 Monitor 是依赖于底层的操作系统实现,存在用户态与内核态之间的切换(可以理解为上下文切换),所以增加了性能开销。

7、有了synchronized ,还需要volatile做什么事?
。一方面是因为synchronized是一种锁机制,存在阻塞问题和性能问题,而volatile并不是锁,所以不存在阻塞和性能问题;
。另外一方面,因为volatile借助了内存屏障来帮助其解决可见性和有序性问题,而内存屏障的使用还为其带来了一个禁止指令重排的附加功能,在某些场景下有它的意义;

JVM相关

1、JVM内存模型

1)内存划分:堆、栈(java、本地)、方法区、计数器。方法区存放类信息、静态变量、常量、运行时常量池;堆主要放数组、对象、字符串常量池;栈是方法运行过程的内存模型。

方法区和堆都是线程共享的,栈和计数器是线程数有的。

2)JVM内存模型,和Java虚拟机运行时区域有关;JAVA内存模型和JAVA并发编程有关。

3)JAVA内存模型:主存(变量) -> 本地内存(变量副本) -> CPU(使用)

4)工作内存与主内存交互:

lock(锁定) -> read(读取) -> load(载入) -> use(使用) -> assign(赋值) -> store(存储) -> write(写入) -> unlock(解锁)

5)内存屏障(Memory barrier):是一种CPU指令,可以让CPU在内存访问上有序,保证屏障之前的指令会先于屏障之后的指令执行,用于控制特定条件下的重排序和内存可见性问题

6)指令重排序:为提高效率,程序在运行时内存实际的访问顺序和程序代码编写的访问顺序不一定一致

2、JVM里的有几种classloader,为什么会有多种?

BootstrapClassLoader -> ExtensionClassLoader -> AppClassLoader -> UserDefinedClassLoader

1)BootstrapClassLoader,负责加载<JAVA_HOME>/lib下的class,开发者不可以直接使用

2) ExtensionClassLoader,负责加载<JAVA_HOME>/lib/ext下的class,开发者可以直接使用

3)AppClassLoader,负责加载用户的class

3、java类加载机制、双亲委派机制、双亲委派模型的好处?

1)类加载的几个阶段:加载、连接(验证、准备、解析)、初始化、使用、卸载。加载的目的是为了获取该类的二进制流

2)双亲委派:如果一个类加载器收到一个类加载的请求,会先将该请求委托给父级类加载器去加载,每一层都是如此。只有父类反馈无法完成这个加载请求时(它的搜索范围内找不到这个类),才会向下委托给子类加载器去加载。

3)双亲委派的好处:自己写的String.java不会覆盖系统的String.java,进而保护系统内部代码。

4、什么情况下我们需要破坏双亲委派模型;

应用隔离,热加载等

1)Tomcat的WebAppClassLoader只会加载自己目录下的class文件,不会交给父类。因为一个Tomcat可以同时装载多个webapp,可防止jar包冲突

2)根据类加载机制,当被装载的类引用了另外一个类的时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类。JDBC的Driver接口定义在JDK中,DriverManager也在JDK中,Driver实现类则在各厂商的实现包中,需要子类去加载。

5、常见的JVM调优方法有哪些?可以具体到调整哪个参数,调成什么值?

答:1)给新生代合理的空间,尽量避免新对象直接进入到老年代

2)大对象进入老年代,减少新生代对大对象的GC。 -XX:PretenureSizeThreshold 设置大对象直接进入老年代的阀值

3)设置对象进入老年代的年龄。-XX:MaxTenuringThreshold:默认值是15

6、什么时候触发FullGC?什么时候触发MinorGC(YoungGC)?

答:触发MinorGC(Young GC)

1、Eden 区内存不足

触发FullGC

。老年代空间不足

如果创建一个大对象,Eden区域当中放不下这个大对象,会直接保存在老年代当中,如果老年代空间也不足,就会触发Full GC。为了避免这种情况,最好就是不要创建太大的对象。

。持久代空间不足

如果有持久代空间的话,系统当中需要加载的类,调用的方法很多,同时持久代当中没有足够的空间,就出触发一次Full GC

。YGC时jvm会检查晋升老年代对象的平均内存大小和老年代剩余空间,如果平均大小大于剩余空间,发生一次full gc,如果平均大小小于剩余空间,检查是否设置允许担保失败,如果不允许,执行一次full gc,反之则不执行。在老年代内存占满时发生一次FULL GC,每次FULL GC都伴随一次minor GC

。显示调用System.gc

7、JVM垃圾收集算法、垃圾收集器、class文件结构是如何解析的

垃圾回收算法

a) 标记-清除算法:分成标记阶段(将要回收的做标记)和清除阶段(将标记的清除)。优点:简单易实现。缺点:碎片多,导致大对象空间不足触发垃圾回收。

b) 标记-整理算法:将内存划分为大小相等的两块,标记并复制到另一块区域。优点:内存利用率高。缺点:空间占用大;如果存活对象很多,复制效率低下。

c) 复制算法:将存活的对象复制到另一个区域

d) 分代收集算法:根据对象生命周期划分为多个区域,新生代(Eden8、Survivor1:1,复制算法)、老年代(标记整理)、永久代。

 

Java扩展

1、红黑树的实现原理和应用场景;

遵循以下特性:

根节点为黑色

所有叶子节点为黑色

从一个节点到所有叶子节点的黑节点数都是相等

红节点的两个子节点都是黑色

在treeMap 和treeSet 中有使用 

HashMap 在单个数组元素下链表长度大于8时也会使用

2、NIO是什么?适用于何种场景?

NIO:no blocking io 非阻塞io

图片查看。。。

3、Java9比Java8改进了什么;

没用过java9。。。。

4、HashMap内部的数据结构是什么?底层是怎么实现的?

entry数组+链表或者 entry数组+红黑树 

当hashmap调用put方法时,首先对key的hash值与entry数组长度取模运算

获取到对应的下标位置,然后遍历链表中的key,如果key和hash都和传入的key相等,替换传入值,如果没有相等则在链表尾部插入新的节点(java 6之前是插入表头)

5、说说反射的用途及实现,反射是不是很慢,我们在项目中是否要避免使用反射;

反射允许动态的绑定类、方法、字段以及其他元素,通过反射可以在运行时完成创建实例、调用方法、访问变量的工作。

反射的实现:object.getClass()、XXX.class 、Class.forName(xxx) 、classloader.loadclass(xxx)

反射运行在jvm上性能有所下降,但并不影响反射的使用,在很多框架中有使用,例如 spring IOC 、JDBC加载驱动等都有用到

6、说说自定义注解的场景及实现;

比如增加业务日志,数据库事务等

7、List和Map区别,Arraylist与LinkedList区别,ArrayList与Vector 区别;

List是数组结构接口,Map是K-V结构接口;ArrayList是线性数组,查询快,插入删除慢,LinkedList是链表结构,查询慢,插入删除快;ArrayList 是线程不安全的,Vector是线程安全的,扩容时ArrayList是增加50%,Vector是增加一倍;

8、Java并发包都有哪些,性能怎样?

java.util.concurrent.locks

java.util.concurrent.atomic
9、什么是fail-fast ?
快速失败:当我们在遍历集合元素的时候,经常会使用迭代器,但在迭代器遍历元素的过程中,如果集合的结构被改变的话,就会抛出异常,防止继续遍历。这就是所谓的快速失败机制。
10、什么是fail-safe ?

当集合的结构被改变的时候,fail-safe机制会再复制原集合的一份数据出来,然后在复制的那份数据遍历
11、什么是CopyOnWrite 

当对象有变化时复制一份对象用来写入,原对象可以继续读取。
12、什么是AQS呢?

AQS (AbstractQuenedSynchronizer)抽象的队列式同步器。是除了java自带的synchronized关键字之外的锁机制,这个类在java.util.concurrent包下。AQS定义了一套多线程访问共享资源的同步器框架。

AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配。

通俗来说,AQS就是基于CLH队列锁实现的,用volatile修饰共享变量state,用CAS(CompareAndSwap)来改变state。state改变成功,则获得锁;改变失败,则进入CLH队列,等待被唤醒。

13、什么是CAS呢?

compare and swap 比较并替换,比较传入的值是否与对象当前的值相等,如果相等,使用新的值替换,这是乐观锁的一种实现方式。
14、乐观锁悲观锁区别是什么?

乐观锁:乐观锁采取了更加宽松的加锁机制。也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。

悲观锁:总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。

15、Hash一致算法?

16、说说HashMap和ConcurrentHashMap的区别?treemap和HashMap的区别?

HashMap 是线程不安全的,ConcurrentHashMap 线程安全,treeMap 实现了Key的排序,HashMap是无序

17、java指针

1-句柄访问

虚拟机如果使用句柄访问方式,Java堆中首先会划分出一块内存作为句柄池,这时候对象引用reference存储的就是对象的句柄地址而不是作为对象指针指向堆中对象的地址,而句柄池中的对象实例包含指向对象实例数据和类型数据的指针,采用句柄访问方式要获得完整的对象信息需要进行三次指针定位。
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FSZWFsbHlNYW4=,size_16,color_FFFFFF,t_70

2 - 直接指针访问

直接指针访问对象,Java虚拟机需要在堆中为对象分配额外的空间存储指向方法区对象类型数据的指针,采用直接指针访问方式,对象引用直接存储堆中对象的地址,只需要进行两次指针定位。目前hot spot就是采用这种对象访问方式。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FSZWFsbHlNYW4=,size_16,color_FFFFFF,t_70

 

3 - 两种对象访问方式对比

两种方式各有优劣,使用句柄访问的好处是在每次对象位置发生变动时只需要改变句柄中指向实例数据的指针,而指向对象类型数据的指针和对象引用指针reference都不需要修改,而使用直接指针访问,当对象发生移动时对象引用reference需要修改。但是使用直接指针访问方式少了一次指针定位的时间开销速度更快。 


 

Spring

1、Spring AOP的实现原理和场景;(应用场景很重要)

Spring Aop 的使用代理方式实现,包括动态代理和静态代理,动态代理两种实现方式,一为JDK自带的代理模式(代理原理是继承Proxy代理类,因为类是单继承的,所以被代理类不能为类必须为接口),二为Cglib代理实现方式(原理是通过生成对应被代理类的字类,并修改字节码文件来实现),应用场景:AOP实现业务操作日志、实现数据库事物等。

2、Spring bean的作用域和生命周期;

 

3、Spring Boot比Spring做了哪些改进?

Spring boot 依赖spring 容器,根据约定优于配置的设计思想,大量使用了默认配置文件,开箱即用,减少开发人员配置时间。

4、Spring IOC是什么?优点是什么?

IOC:控制反转,javabean的对象由原来的程序员创建交由spring容器来通过反射创建,spring容器启动时会获取配置文件将javabean通过反射创建对应的实例并保存在一个map中,map的key就是ID,在程序调用时,通过反射调用对象对应的setter方法赋值。对象的实际类型由容器决定,从而降低代码的耦合度。

5、SpringMVC、动态代理、反射、AOP原理、事务隔离级别;

AOP:切面编程,java的面向对象思想支持上下扩展(继承),对于水平扩展欠缺,spring的aop正是为了解决这个问题应运而生的。在不同逻辑代码中实现相同的操作,例如数据库事物编程、日志功能等。AOP的实现有两种方式,1是通过静态织入(静态织入是指对每一个要实现切面编程的接口实现一个代理类,在代理类中实现切面方法),2动态代理(动态代理有两种方式分别为JDK自带的动态代理方式和CGLIB动态代理方式,JDK动态代理的使用前提是代理类必须实现接口,因为Java是单继承的,而代理类又必须继承自Proxy类,所以通过jdk代理的类必须实现接口

事物的隔离等级:

 

是否会脏读

是否会重复读

是否会幻读

Defined

 

 

 

Read Uncommitted

Read Committed

Repeatable Read

Serializable

Mysql的默认等级是Repeatable Read

Oracle只用两种等级 read committed(默认) 和serializable

事物的传播等级:

Propagation_requried 如果当前存在事物,加入的当前事物,如果当前不存在事物,新建事物,父事物失败和子事物失败都会回滚,子事物必须在父事物成功才能提交(这里貌似就一个事物)

Propagation_supports 如果当前存在事物,加入当前事物,如果不存在,以非事物方式执行

Propagation_requires_new 直接新建一个事物,如果当前存在事物,挂起当前事物,如果子事物失败不影响父事物

Propagation_nested 是Propagation_required和propagation_requires_new 的结合,子事物必须在父事物成功才能commit,子事物不影响父事物提交(save point控制)

Propagation_not_supported 当前存在事物则挂起事物,执行当前逻辑,结束后恢复当前事物。

Propagation_mandatory 如果上下文不存在事物则抛出异常,这种方式是某个方法不能单独执行,必须在一个事物内部调用。

Propagation_never 当前不能存在事物,如果存在则抛出runtime异常

中间件

1、Dubbo完整的一次调用链路介绍;

客户端以本地服务方式调用服务

客户端通过代理方式将调用接口与调用的参数处理成请求数据

客户端发送调用数据到远端的系统,通过TCP或UDP

服务端处理客户端发过来的调用与参数

服务端调用真正提供的服务

服务端处理回复,然后发送给客户端

2、Dubbo支持几种负载均衡策略?

.随机模式。按权重设置随机概率。在一个截面上碰撞的概率较高,但调用越大分布越均匀

.轮询模式。按公约后的权重设置轮询比例。但存在响应慢的服务提供者会累积请求

.最少活跃调用数。响应快的提供者接受越多请求,响应慢的接受越少请求

.一致hash。根据服务提供者ip设置hash环,携带相同的参数总是发送的同一个服务提供者,若服务挂了,则会基于虚拟节点平摊到其他提供者上

3、Dubbo Provider服务提供者要控制执行并发请求上限,具体怎么做?

配置executes

4、Dubbo启动的时候支持几种配置方式?

xml配置

dubbo.properties

api方式

注解方式

5、了解几种消息中间件产品?各产品的优缺点介绍;

Rocketmq,activeMq

6、消息中间件如何保证消息的一致性和如何进行消息的重试机制?

 

数据库篇

1、锁机制介绍:行锁、表锁、排他锁、共享锁;

行锁和表锁是对数据上锁的粒度不同,InnoDB使用的是行级锁,MyISAM使用的是表级锁。InnoDB select * from table for update 不加条件时也是表级别锁。

排他锁:如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。InnerDB 在insert、update、delete 操作时默认都加上排他锁;SQL:select ....for update

共享锁:一个事务获取了共享锁,其他事务可以获取共享锁,不能获取排他锁,其他事务可以进行读操作,不能进行写操作。SELECT ... LOCK IN SHARE MODE

2、乐观锁的业务场景及实现方式

在数据表中加version版本号实现乐观锁

3、事务介绍,分布式事物的理解,常见的解决方案有哪些,什么事两阶段提交、三阶段提交;

分布式事务的解决方案:

两阶段提交2PC、三阶段提交3PC,Try - Confirm - Cancel(TCC)、本地消息表、消息事物、最大努力通知

事务两阶段提交的过程如下:
● 两阶段提交在应用程序向协调者发出一个提交命令时被启动。这时提交进入第一阶段,即预提交阶段。在这一阶段中:
(1) 协调者准备局部(即在本地)提交并在日志中写入"预提交"日志项,并包含有该事务的所有参与者的名字。
(2) 协调者询问参与者能否提交该事务。一个参与者可能由于多种原因不能提交。例如,该Server提供的约束条件(Constraints)的延迟检查不符合 限制条件时,不能提交;参与者本身的Server进程或硬件发生故障,不能提交;或者协调者访问不到某参与者(网络故障),这时协调者都认为是收到了一个 否定的回答。
(3) 如果参与者能够提交,则在其本身的日志中写入"准备提交"日志项,该日志项立即写入硬盘,然后给协调者发回,已准备好提交"的回答。
(4) 协调者等待所有参与者的回答,如果有参与者发回否定的回答,则协调者撤消该事务并给所有参与者发出一个"撤消该事务"的消息,结束该分布式事务,撤消该事务的所有影响。

● 如果所有的参与者都送回"已准备好提交"的消息,则该事务的提交进入第二阶段,即决策后提交阶段。在这一阶段中:
(1) 协调者在日志中写入"提交"日志项,并立即写入硬盘。
(2) 协调者向参与者发出"提交该事务"的命令。各参与者接到该命令后,在各自的日志中写入"提交"日志项,并立即写入硬盘。然后送回"已提交"的消息,释放该事务占用的资源。 
(3) 当所有的参与者都送回"已提交"的消息后,协调者在日志中写入"事务提交完成"日志项,释放协调者占用的资源 。这样,完成了该分布式事务的提交。

     现如今实现基于两阶段提交的分布式事务也没那么困难了,如果使用java,那么可以使用开源软件atomikos来快速实现。

4、JDBC如何实现事务、嵌套事务实现、分布式事务实现;

 

5、SQL的整个解析、执行过程原理、SQL行转列;

行转列:使用 case when 语句。

例如: select 学生号,  
sum(case 科目 when '语文' then 成绩 end) as 语文,  
sum(case 科目 when '数学' then 成绩 end) as 数学,  
......  
from table  
where ...  
group by 学生号  

6、数据库如何实现悲观锁和乐观锁?

悲观锁:select * from table for update ,行锁、表锁、读锁、写锁等,都是在操作之前先上锁。

乐观锁:使用版本号,修改时判断当前版本是否最新,如果最新的直接修改
7、数据库锁和隔离别有什么关系?

隔离级别依赖锁实现

RU-读为提交 :事务在修改数据的时候加共享锁,提交后释放(解决了修改时,数据被删除或修改的情况)

RC-读已提交:事务在修改某数据时会加上写锁,直到事务结束再释放,这样的机制保证了RC隔离级别不会发生脏读,只有提交过的事务,才能被其他事务看见

RR-重复读:事务在修改数据的时候加写锁,并且Mysql采用了间隙锁,但触发间隙锁的前提是(查询条件列不可以是唯一索引和主键),在触发间隙锁后,会锁住一定范围内的数据,防止在这范围内插入数据,这个机制可以在一定程度上降低发生幻读的可能

Serializable:

事务在读取数据时,对整个表加读锁,提交或回滚事务后释放

事务在修改数据时,对整个表加写锁,提交或回滚事务后释放

这是最高的隔离级别,可以解决脏读,不可重复读和幻读,但同时效率也是最差的一个。它解决这些由于事务并发带了的问题的方法就是把这些操作变成串行操作,一旦不符合条件,就会被阻塞,所以效率特别差。
8、数据库锁和索引有什么关系?

没关系
9、什么是聚簇索引?

即索引和rowdata 存放在同一地址块内,查到索引即可取到数据。
10、什么是非聚簇索引?

聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。

11、索引最左前缀是什么?

即当有多个字段组成的联合索引时,查询如果要使用索引,必须是从左往右不可缺少字段才能生效,例如a、b、c联合索引 ,查询使用a、b 可以使用索引,如果查询b、c则不会使用索引
12、什么是B+树素引?

平衡二叉树索引的升级版本,B+树的索引都在叶子节点,且相邻索引使用指针关联。方便范围查找。
13、什么是联合索引?

联合索引是指由多个字段组合成的一个索引
14、什么是回表?回表是指在查询中查询并不是直接查询到结果集,他们先查到对应主键的索引然后还需通过主键索引在做一次查询获得结果集。

 

Redis

1、Redis为什么这么快?redis采用多线程会有哪些问题?

redis是运行在内存中

redis采用了react多路复用模型

redis使用单线程,避免线程上下文切换

2、Redis支持哪几种数据结构;

String、list 、set 、sortset、hashmap

3、为什么要用Redis ?

提高性能,系统访问数据的速度是比较耗时的,redis是内存访问,速度快

4、Redis单进程单线程的Redis如何能够高并发?

redis是在内存中运行,它的性能瓶颈是内存,不是cpu

5、Redis如何使用Redis实现分布式锁?

setNX :set if not exist

6、Redis分布式锁操作的原子性,Redis内部是如何实现的?

使用单线程避免线程竞争

7、Redis跳跃表的问题;

 

 

Tomcat

1、Tomcat类加载机制

1)Tomcat不遵循双亲委派模型;

2)隔离性。同一个Tomcat可同时装载不同版本的jar包,互不影响

 

CMS和G1了解吗?

 

CMS回收停顿了几次?

停顿了2次 :第一次是初始标记阶段,该阶段标记根root对象直接关联的对象,第二次是重复标记阶段,该阶段是对并行阶段产生的对象重新重新标记。

java栈什么时候会内存溢出,java堆呢,说一种场景?

java栈:调用方法有循环调用无法结束,java堆:或者有频繁创建对象

集合类如何解决这个问题(软引用和弱引用),讲下这个两个引用的区别?

软引用(SoftReference)【当内存不足,将它当成垃圾回收】

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

弱引用(WeakReference)【垃圾,由JVM中的垃圾回收器发现并回收】

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

java里的锁了解哪些?

乐观锁、悲观锁、排他锁、共享锁、偏向锁、轻量锁、重量锁

synchronized锁升级的过程(偏向锁到轻量锁再到重量级锁),分别如何实现的,解决的是哪些问题?

 

什么是类加载器?

用于将java.class文件加载成虚拟机可以识别的二进制文件

GC的机制是什么?GC算法和回收策略

垃圾回收机制:JVM有一个垃圾回收线程,它是低优先级的,JVM根据root搜索法搜索到对象到GC root都没有引用,则第一次标记为可以GC,然后检查该对象是否需要执行finalize的方法(覆盖finalize()),如果没有覆盖finalize方法,或者有覆盖但已经执行过finalize方法直接GC掉,如果覆盖了finalize方法但没有执行该方法,将对象放入到F-QUEUE队列中,由低一级的线程去调用该对象的finalize方法,如果调用后还是无法到达则GC掉。

GC算法

  1. 标记-清除:
    这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:1.效率不高,标记和清除的效率都很低;2.会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。
  2. 复制算法:
    为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然后一次性清除完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一半的内存。
    于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)
  3. 标记-整理
    该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候先将可回收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了。
  4. 分代收集 
    现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除

在 Java 语言中,可作为 GC Root 的对象包括以下4种

  • ①虚拟机栈(栈帧中的本地变量表)中引用的对象
  • ②方法区中类静态属性引用的对象
  • ③方法区中常量引用的对象
  • ④本地方法栈中 JNI(即一般说的 Native 方法)引用的对象

什么时候多线程会发生死锁,写一个例子?

死锁产生的四个条件

互斥条件:该资源任意一个时刻只由一个线程占用;

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源持有不释放;

不剥夺条件:线程已获得的资源,在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源;

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

同理,只要任意破坏产生死锁的四个条件中的其中一个就可以了:

1.破坏互斥条件:该条件没有办法破坏,因为用锁的意义本来就是想让他们互斥的(临界资源需要互斥访问);

破坏请求与保持条件:一次性申请所有的资源;

破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源;

破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。

 

Redis的数据结构是什么?线程模型说一下?

redis5种数据结构:string、list、set、sort set 、hashmap 

redis使用的是reactor 多路复用模型

讲讲Redis的数据淘汰机制?

redis的淘汰机制是指在内存不足的情况下,redis如何淘汰数据,包括以下方式

noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。

allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。

allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。

volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。

volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。

volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。

说说Redis的数据一致性问题?

多数据库操作一定会存在一致性问题

  1. 先更新数据库,再更新缓存
  2. 先删除缓存,再更新数据库
  3. 先更新数据库,再删除缓存

RPC讲一下

RPC原理在服务端启动时接受注册信息,并通过线程池等待远程请求,通过远程请求的数据通过反射调用本地的接口实现,然后通过远程响应将结果发送给客户端,客户端通过动态代理获取远程代理类调用对应的方法得到返回结果(这里的远程通讯可以是BIO、NIO、HTTP各种形式),dubbo的实现原理基本雷同,dubbo使用 Netty异步高性能的通信框架作为基础通讯组件。

三次握手和四次挥手?如果没有三次握手有问题吗?

 

事务的特性及慢查询?

A-原子性;C-一致性;I-隔离性;D-持久性

BTree机制说一下?

 

说说MySQL常用的优化方法?

优化的开销从低到高:SQL优化->索引优化->表结构优化->读写分离->分表分库

cap了解吗,分别指什么?

C-Consistency:一致性,分布式系统中对多个数据源的改动保证所有数据一致。

A-Availability:可用性,分布式系统中在网络出现故障等情况下要保证系统能够正常返回结果。

P-Partition tolerance:分区容错,在网络出现故障等情况导致网络分区下(部分间网络不通),系统还能继续运行,不会挂掉。

缓存雪崩说下?

设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到 DB, DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个key 缓存

MySQL主从复制怎么实现的?具体原理是什么?有什么优缺点?

e1cea5e3c937fc2b80c4591f2abc58cb.gif

主从复制原理 

  1. slave端的IO线程连接上master端,并请求从指定binlog日志文件的指定pos节点位置(第一次复制完成的日志文件)开始复制之后的日志内容
  2. master端在接收到来自slave端的IO线程请求后,通知负责复制进程的IO线程,根据slave端IO线程的请求信息,读取指定 binlog日志指定pos节点位置之后的日志信息,然后返回给slave端的IO线程。该返回信息中除了binlog日志所包含的信息之外,还包括本次返回的信息在master端的binlog文件名以及在该binlog日志中的pos节点位置。
  3. slave端的IO线程在接收到master端IO返回的信息后,将接收到的binlog日志内容依次写入到slave端的relaylog文件(mysql-relay-bin.xxxxxx)的最末端,并将读取到的master端的binlog文件名和pos节点位置记录到master- info(该文件存在slave端)文件中,以便在下一次读取的时候能够清楚的告诉master,我需要从哪个binlog文件的哪个pos节点位置开 始,请把此节点以后的日志内容发给我。
  4. slave端的SQL线程在检测到relaylog文件中新增内容后,会马上解析该log文件中的内容。然后还原成在master端真实执行的那些SQL语句,并在自身按顺序依次执行这些SQL语句。这样,实际上就是在master端和slave端执行了同样的SQL语句,所以master端和 slave端的数据是完全一样的。

好处

  1. 数据更安全:做了数据冗余,不会因为单台服务器的宕机而丢失数据
  2. 性能大大提升:一主多从,不同用户从不同数据库读取,性能提升
  3. 扩展性更优:流量增大时,可以方便的增加从服务器,不影响系统使用
  4. 负载均衡:一主多从相当于分担了主机任务,做了负载均衡。

缺点

    1 .数据库存在一致性问题

 

消息队列,用到什么场景

(削峰,限流,异步)

讲了下kafka,怎么保证数据不丢失?确保消息不会重复消费?

 

消息送达确认是怎么实现的?

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值