嘘~ 正在从服务器偷取页面 . . .

2021年Java 面试题


Java面试题及答案

2020年10月23日整理

1、说说枚举和单例

枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,它既是一种类(class)类型却又比类类型多了些特殊的约束。枚举可以避免反射和序列化问题,编译器会严格类型检查,

单例是一种创建型的设计模式,单例模式保证内存中只有一个实例对象,避免对象实例创建于销毁,减少内存开销,避免对资源的多重占用。

单例三个特点:(1)构造方法私有化;(2)实例化的变量引用私有化;(3)获取实例的方法公有

单例实现方式:(1)饿汉式(2)懒汉式(加锁)(3)静态内部类(4)枚举单例

2、怎么理解死锁

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法向下执行。。比如有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁,这个世界就容易产生死锁。

产生死锁的原因

a. 竞争资源

系统中的资源可以分为两类:
可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;另一类资源是不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。

产生死锁中的竞争资源之一指的是竞争不可剥夺资源(例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞)
产生死锁中的竞争资源另外一种资源指的是竞争临时资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁

b. 线程间推进顺序非法

若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁
例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁。

产生死锁的4个必要条件:

  • 互斥条件:线程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为某一个线程所占用。
  • 请求和保持条件:当线程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:线程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
  • 环路等待条件:在发生死锁时,必然存在一个线程资源的环形链。

解决死锁的基本方法

预防死锁:

(1)资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)
(2)只要有一个资源得不到分配,也不给这个线程分配其他的资源:(破坏请保持条件)
(3)可剥夺资源:即当某个线程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
(4)资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

(1)、以确定的顺序获得锁。对锁进行hash排序,使用银行家算法保证系统安全

(2)、超时放弃策略,使用Lock接口的tryLock()方法,在一定时间内获取不到锁就放弃已经获得的锁。

3、对jvm的理解

JVM是Java虚拟机的缩写,是跨语言的平台。一般会把JVM整体结构分三层,第一层是前端编译器将源文件编译成class文件,再由类装载器子系统将class文件加载到内存。第二层是运行时数据区,线程共享分方法区和对,线程私有区分栈和程序计数器。第三次是执行引擎来解释运行,执行引擎包括解释器,实时编译器(编译缓存区),垃圾回收器。

JVM生命周期有三个:启动–执行–退出。

Java虚拟机的启动是通过引导类加载器创建一个初始类来完成,这个类是 有虚拟机的具体实现指定的。程序开始执行的时候,java虚拟机就在执行。虚拟机退出,正常执行结束或者出现异常或错误,或者调用System的exit方法,Runtime的halt方法。

4、SpringCloud 技术体系

服务注册与发现:Eureka,Consul,Zookeeper,Nacos

服务调用负载均衡:Restful + Ribbon,Nginx RPC,gRPC

服务接口调用:Feign

服务熔断:Hystrix,sentinel

服务,Gateway

5、HashMap在1.8里和1.7有什么不同

不同

(1)底层结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构;

(2) jdk1.7中当哈希表为空时,会先调用inflateTable()初始化一个数组;而1.8则是直接调用resize()扩容;

(3)插入键值对的put方法的区别,而1.7中是采用头插;1.8中会将节点插入到链表尾部,

(4)jdk1.7中的hash函数对哈希值的计算直接使用key的hashCode值,而1.8中则是采用key的hashCode异或上key的hashCode进行无符号右移16位的结果,避免了只靠低位数据来计算哈希时导致的冲突,计算结果由高低位结合决定,使元素分布更均匀;

(5)扩容时1.8会保持原链表的顺序,而1.7会颠倒链表的顺序;而且1.8是在元素插入后检测是否需要扩容,1.7则是在元素插入前;

(6)扩容时机:jdk1.8是扩容时通过hash&cap==0将链表分散,无需改变hash值,而1.7是通过更新hashSeed来修改hash值达到分散的目的;

(7)扩容策略:1.7中是只要不小于阈值就直接扩容2倍;而1.8的扩容策略会更优化,当数组容量未达到64时,以2倍进行扩容,超过64之后若桶中元素个数不小于7就将链表转换为红黑树,但如果红黑树中的元素个数小于6就会还原为链表,当红黑树中元素不小于32的时候才会再次扩容。

6、线程池怎么创建,有哪几个参数,分别是什么作用

使用 Executors 类创建线程池;使用 ThreadPoolExecutor 创建。

七个参数:核心线程数、最大线程数、存活时间、单位、任务队列、线程工厂、拒绝策略。

7、main 方法里启动了两个线程,怎么让两个线程都执行完,再继续执行main线程

countDownLatch 这个类使一个线程等待其他线程各自执行完毕后再执行。

8、web容器相关,tomcat启动有哪几个端口,分别是什么作用

8080(8443)端口

<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000"  redirectPort="8443" />

链接器Connector用于监听浏览器发送的请求的。http协议,其中redirectPort表示如果发送的是https请求,就将请求发送到8443端口。
8443是默认的https监听端口,默认是没有开启的,如果要开启由于tomcat不自带证书所以除了取消注释之外,还需要自己生成证书并指定。

8009端口

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Nginx、Apache等反向代理tomcat时就可以使用ajp协议反向代理到该端口。
虽然我们经常使用http反向代理到8080端口,但由于ajp建立tcp链接后一般长时间保持,从而减少Http反复进行tcp链接和断开的开销,所以反向代理中ajp是比http高效的。

8005端口

<Server port="8005" shutdown="SHUTDOWN" >

tomcat监听的关闭端口,就是说这个端口负责监听关闭tomcat的请求。

当执行shutdown.sh关闭tomcat就是链接8005端口执行SHUTDOWN命令;由此,我们直接用telnet向8005端口执行SHUTDOWN来关闭tomcat,这也是比较正统的关闭方式,如果这个端口没被监听,那么sh脚本就是无效的。

实际上,8005和8009端口并不是必须的,尤其SHUTDOWN虽然默认是监听在127.0.0.1,但是连接到这个端口,发送SHUTDOWN就可以无任何验证的把tomcat关闭掉,有安全隐患的。

9、@Transaction有没有可能会失效?如果事务方法是private还会生效吗

失效的情况:

(1)@Transactional 应用在非 public 修饰的方法

(2)@Transactional 注解属性 propagation 设置错误:PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER

(3)@Transactional 注解属性 rollbackFor 设置错误

(4)使用 try-catch 处理了异常

(5)同一个类中方法methodA没有声明注解事务,而methodB方法有那么在外部调用方法methodA之后,方法methodA的事务是不会起作用的。

(6)数据库不支持

10、redis 设计一下库存怎么做

11、redis分布式锁怎么实现

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid),它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。

12、redis 基本数据结构有哪些

redis一共分为5中基本数据类型:String, Hash, List, Set, ZSet

(1)String类型是包含很多种类型的特殊类型,并且是二进制安全的。比如序列化的对象进行储存,比如一张图片进行二进制储存,比如一个简单的字符串数值等等。

(2)Hash类型是String类型的filed和value的映射表,或者说是一个String的结合,他特别适合存储对象。相比较而言把一个对象存储在Hash类型中要比直接存储在String中更加节省空间。并方便存储整个对象,Hash类型也是我们工作中最常用的一种。

(3)List类型是一个链表结构的集合,其主要功能有push,pop获取元素等等。更详细的说List类型是一个双端链表结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素。List的设计非常简单精巧,既可以作为栈又可以作为队列。

(4)set集合是String类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集。

(5)Zset是在set的基础上做了一个有序的调整。

13、maven 的打包是什么命令?package和install 作用是什么,怎么部署包到远程仓库?

package 打包

install 打包并发布到本地仓库

deploy 打包并部署

14、git常用命令有哪些?怎么合并分支

git add

git commit -m

git push

git merge

15、spring cloud config怎么用

SpringCloud Config 为微服务架构中的各个微服务提供集中式的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置

一个config服务端,其他使用配置应用作为客户端,从服务器配置中心获取最新配置,实现配置变动的实时生效。

16、nginx 反向代理怎么配置

server 监听server_name ,location 中配置 proxy_pass 访问实际地址

17、nginx访问路径文件夹没有权限怎么办?修改组的权限命令是什么

chmod

chown -R 所有者用户名.组名 文件夹名称

2020年10月28日整理

1、sql优化除了SQL语句和索引还可以做哪些?

(1)表设计的时候列选择合适的数据类型

(2)使用 EXPLAIN 关键字去查看执行计划

(3)选择合适的数据集引擎

2、现在有个业务,需要同时满足几种不同的条件才能走下去,并且几种条件会经常变化,你怎么设计?

可以使用策略模式,条件变化时,创建新的条件类实现策略接口,利用多态来实现新的条件使用,如果条件过多,可以使用混合模式,比如用工厂来生成策略,用外观模式屏蔽策略细节。

3、web.xml 可以配置哪些东西

(1)ServletContext初始化参数,

(2)Session会话配置,Servlet声明配置,

(3)应用声明周期监听器,

(4)过滤器定义与映射,

(5)欢迎页面列表

(6)MIME类型映射

(7)错误页面

(8)字符集编码

(9)安全配置

4、web应用启动时组件的加载先后顺序

(1)web应用启动Servlet容器,加载读取web.xml文件。

(2)ContextLoaderListener应用上下文监听初始化

(3)IOC容器初始化,使用XmlWebApplicationContext 加载对应配置的applicationContext.xml 配置文件,进入IOC容器管理 bean 的过程

(4)进入SpringMVC 启动环节,收集@GetMapping 地址完成资源路径映射的注册

(5)URL映射注册完成之后,开始初始化DispatcherServlet

(6)Session 监听初始化

(7)Servlet容器里 的 ProtocolHandler 协议处理器启动,开始监听Sekcet 请求

5、jvm调优使用的参数有哪些,分别是什么意思

-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3表示年轻代和年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如3表示Eden: 3 Survivor:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
-XX:MataspaceSize=32M  设值元空间大小,默认值大约21M
-XX:MaxTenuringThrehold=15 晋升老年代的最大年龄,默认是15

收集器设置
 -XX:+UseSerialGC:设置串行收集器
 -XX:+UseParallelGC:设置并行收集器
 -XX:+UseParalledlOldGC:设置并行年老代收集器
 -XX:+UseConcMarkSweepGC:设置并发收集器

打印GC日志
-XX:+PrintGC 
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename

6、说下springboot 自动化配置加载

7、说说Spring bean的生命周期

8、innodb有哪些特点

9、Mysql 索引原理,外键索引

10、数据库建表需要注意哪些事情?

11、Spring cloud的Feign 的做什么的,怎么实现的

12、Ribbon 负载均衡策略有哪些?轮询算法的逻辑是怎么样?

13、线程池的几个参数和作用,怎么判断是不是核心线程

14、synchronized 锁膨胀过程,锁升级过程,底层原理

15、类加载过程是怎样的?

16、双亲委派模型是怎样,怎么破坏的

17、什么是粗化锁

18、线程池主要参数和工作原理

2020年10月30日整理

1、spring mvc 请求到响应的过程

2、HashMap在1.8里和1.7有什么不同

3、字符串比较,==和equles

4、Mysql 索引原理及分类,BD2 索引有哪些?

5、HashTable 和 ConcurrentHashMap 区别

6、单节点应用,按钮点击后端只能查询一次,后端怎么处理

7、参数传递,值传递和引用传递

8、储过程和函数有什么区别

9、分布式锁实现方法

10、分布式事务原理

11、redis持久化问题

12、Hystrix等限流原理(令牌桶,漏斗算法)

13、BIO和NIO

14、jvm哪几种引用类型

15、spring 和spring boot 有什么区别

2020年11月

1、execute和submit的区别

execute和submit都属于线程池的方法,execute只能提交Runnable类型的任务,而submit既能提交Runnable类型任务也能提交Callable类型任务。

execute会直接抛出任务执行时的异常,submit会吃掉异常,可通过Future的get方法将任务执行时的异常重新抛出。

execute所属顶层接口是Executor,submit所属顶层接口是ExecutorService,实现类ThreadPoolExecutor重写了execute方法,抽象类AbstractExecutorService重写了submit方法。

2、JVM运行时内存布局,各个区大小

3、常见的OOM,SOF以及预防措施

4、CAP理论-BASE理论

5、设计原则和设计模式,设计模式的使用

6、分布式事务

7、Redis使用 MQ使用

8、手写单例

9、为什么HashMap的加载因子是0.75

10、为什么volatile 不能保证原子性?

11、ReentrantLock 加锁原理(AQS+CAS)

12、聚簇索引和非聚簇索引

13、你的优势是什么?你最擅长什么?

14、什么是程序员?程序员是什么的?

15、设计模式有什么好处?

其他

后面有些没有及时记录,没想起来,如果想起来来再补充。

不需要背答案,把每个知识点真正的搞懂才是最重要的。



文章作者: Small-Rose
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明来源 Small-Rose !
评论
  目录