跟着B战学习JAVA面试八股文
- 创建线程的几种方式?
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 通过线程池来创建线程
- 为什么不建议使用Executors创建线程池?
以创建FixedThreadPool为例,其构造方法为:
public static ExecutorService newFixedThreadPool (int nThread) {
return new ThreadPoolExecutor (nThread, nThread, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
发现创建的队列为LinkedBlockingQueue,是一个无界阻塞队列(最大是21亿个任务),如果使用该线程池执行任务,如果任务过多就会不断的添加到队列中,任务越多占用的内存就越多,最终可能耗尽内存,导致OOM。
// 短信关于创建线程池的实践,线程池的大小要结合具体的场景来确定。
private static final ExecutorService executor;
static {
Integer corePoolSize = DeviceConfig.getInstance().getInteger("route.exec.corePoolSize", 16);
Integer maximumPoolSize = DeviceConfig.getInstance().getInteger("route.exec.maximumPoolSize", 16);
Integer queueCapacity = DeviceConfig.getInstance().getInteger("route.exec.queueCapacity", 1000);
executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(queueCapacity),
Executors.defaultThreadFactory(), new CallerRunsPolicyWithCounter());
}
// 拒绝策略,计数
public class CallerRunsPolicyWithCounter implements RejectedExecutionHandler {
private AtomicLong count = new AtomicLong(0L);
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
count.incrementAndGet();
r.run();
}
}
public long report() {
return count.getAndSet(0L);
}
}
- 线程池有几种状态,分别表示什么?
- Running(运行状态):线程池新建或者调用execute()方法后,处于运行状态,能够接收新的任务
- ShutDown(关闭状态):调用shutdown()方法后,此时线程池不再接收新的任务,但会执行已提交的等待队列中的任务.
- Stop(停止状态):调用shutdownNow()方法时,线程的状态会变为Stop。此时线程池不再接收新的任务,并且会中断正在处理中的任务
- Tidying(整理状态):中间状态不做任何处理
- Terminated(终止状态):线程池内部的所有线程都已经终止时,线程池进入Terminated状态
- Synchronized和ReentrantLock有哪些不同点?
- Sync的底层锁升级策略?
- Lock的中断方式?
- ThreadLocal 有哪些应用场景?它底层是如何实现的?
线程隔离
结构如下,每个线程都会关联一个ThreadLocalMap
- ReentrantLock分为公平锁和非公平锁,那底层分别是如何实现的?
首先不管是公平锁和非公平锁,他们的底层实现都是使用AQS来进行排队,他们的区别在于线程在使用lock()方法加锁时:
- 如果是公平锁,会先检查AQS队列中是否存在线程在排队,如果有线程在排队,则当前线程也进行排队;
- 如果是非公平锁,则不会去检查是否有线程在排队,而是直接去竞争锁。
另外,不管是公平锁还是非公平锁,一旦没竞争到锁,都会进行排队,当锁释放时,都是唤醒排在最前面的线程,所以非公平锁只是体现在了线程加锁阶段,而没有体现在线程被唤醒的阶段。
ReentrantLock是可重入锁,不管是公平锁,还是非公平锁都是可重入。
- Synchronized 的锁升级过程是什么样的?
- tomcat 为什么要自定义类加载器?
避免因为类名一样而产生冲突。
- 微服务有什么好处?
单体项目的缺点:
- 可扩展性受限
- 难以维护和更新
- 高风险
- 技术栈限制
- 团队协助复杂
微服务项目的缺点:
- 成本挑战
i. 基础设施成本增加
ii. 开发和维护成本- 复杂性挑战
i. 分布式系统复杂性
ii. 服务发现与治理- 部署挑战
i. 自动化部署需求
ii. 版本控制和回滚- 一致性挑战
i. 数据一致性
ii. 事务管理- 监控与故障排查挑战
i. 性能挑战
ii. 故障排查
- 现在有哪些微服务解决方案?
- Dubbo + ZK
- SpringCloud
- Eureka 实现原理了解吗?
Eureka的实现原理,可以分为以下几个方面:
- 服务注册与发现:当一个服务实例启动时,会向Eureka Server发送注册请求,将自己注册到注册中心。Eureka Server会将这些信息保存在内存中,并提供REST接口供其他服务查询。服务消费者可以通过查询服务实例列表来获取可用的服务提供实例,从而实现服务的发现。
- 服务健康检查:Eureka通过心跳机制来检测服务实例的健康状态。服务实例会定期向Eureka Server发送心跳,也就是续约,以表明自己的存活状态.如果Eureka Server在一定时间内没有收到某个服务实例的心跳,则会将其标记为不可用,并从服务列表中移除,下线实例。
- 服务负载均衡:Eureka客户端在调用其他服务时,会从本地缓存中获取服务的注册信息.如果缓存中没有对应的信息,则会向Eureka Server发送查询请求.Eureka Server会返回一个可用的服务实例列表给客户端,客户端可以使用负载均衡算法选择其中一个去调用。
- Eureka Server是怎么保证高可用的?
- 多实例部署:通过将多个Eureka Server实例部署在不同的节点上,可以实现高可用性。当其中一个实例发生故障时,其他实例仍然可以提供服务,并保持注册信息的一致性。
- 服务注册信息的复制:当一个服务实例向Eureka Server注册时,每个Eureka Server实例都会复制其他实例的注册信息,以保持数据的一致性。当某个Eureka Server实例发生故障时,其他实例可以接管其工作,保证整个系统的正常运行.
- 自我保护机制:Eureka具有自我保护机制.当Eureka Server节点在一定时间内没有收到心跳时,会进入自我保护模式。在自我保护模式下,Eureka Server 不再剔除注册表中的服务实例,以保护现有的注册信息。这样可以防止由于网络抖动活其他原因导致的误剔除,进一步提高系统的稳定性。
- 什么是CAP?为什么三者不能同时拥有?
分布式项目的3个特性:一致性(Consistency),可用性(Availability)、分区容错(Partition-tolerance)
- 分区容错性:分布式系统在遇到某节点或者网络分区故障时,仍然能够对外提供服务。
- 一致性:所有节点在同一时间的数据完全一致。
- 可用性:服务一直可用,而且是正常响应时间。允许读到的是旧的数据。
- Base理论了解吗?
- Basically Available : 基本可用:
- Soft state:软状态,即允许多个节点存在数据延迟
- Eventually consistent:最终一致性
- 什么是分布式事务?
ACID
- Atomicity: 原子性 一个事务的所有操作,必须全部完成,或者全部不完成。
- Consistency: 一致性 在事务开始或结束时,数据库应该在一致状态。
- Isolation:隔离性 事务与事务之间不会互相影响
- Durability: 持久性 事务一旦完成,就不能返回,变更完全保存到数据库中
- 分布式事务有哪些常见的实现方案?
- 2PC:2阶段 准备-完成 准备-回滚
- 3PC:canCommit + 2阶段
- TCC:Try-Confirm-Cancel 类似2PC,阻塞粒度小 偏重于代码上解决
- SAGA: 流水线事务 == 长事务
- 消息队列实现数据最终一致性
- 有哪些分布式锁的实现方案?
- 基于MySQL来实现分布式锁 :效率不高,频繁操作会增大数据库的开销。
- 基于Redis实现分布式锁
i. setNx 设置值操作成功表示加锁成功,反之,则加锁失败。
ii. Redisson 基于lua脚本来加锁。(看门狗会对过期时间进行延长)
- 基于Zookeeper实现分布式锁
- 类的生命周期
- 加载:将类从class文件加载到JVM中
- 连接:
2.1. 验证:验证格式正确
2.2. 准备:进行必要的初始化:int类型初始化为0,bool类型初始化为false, 静态对象初始化为null
2.3. 解析:字符引用解析为直接引用,比如针对Test这个类,建立从名称到地址的映射- 初始化:创建类的时候,才会进行初始化。比如new、或者调用静态方法
- 使用:即调用
- 卸载:垃圾回收
说明: 加载 ->连接->解析:一定会执行;其他三步只有在执行时,才会执行!!!
- JVM类加载机制
双亲委派机制: 只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去完成加载
作用:保证类的唯一性,只会加载1次(安全性)
-
JVM内存区域
-
对象创建过程了解吗?
-
对象内存分配方式
- 绝对规整:
- 内存不规整:(具体方式由垃圾回收器决定)
i. 指针碰撞
ii. 空闲列表
- JVM创建对象是如何解决多线程内存抢占的?
内存抢占:
- CAS:(Compare And Swap 乐观锁)
- TLAB:(ThreadLocal AllocationBuffer 本地线程分配缓冲)
i. JDK1.8默认是这种方式分配。可以设置参数关闭这个功能。
ii. 如果分配失败,基于CAS分配
- 对象的内存布局与大小计算
- 对象头:
i. 存储对象自身的运行数据,如:哈希码、GC分代年龄、锁状态、线程持有的锁、。。。
ii. 存储对象类型指针,即对象指向类元数据的指针
iii. 如果是数组,对象头还有一块区域记录数据长度的数据。
- 实例数据::代码中定义的字段内容
- 对齐填充(非必须):保证是8字节的倍数
- JVM内存泄露的原因
- 如何判断对象仍然存活?
- 引用计数器
问题:循环引用,实际上没有用到,但是都有被引用。> 2. 可达性分析算法
i. GC roots:线程池常量、静态变量、常量池、JNI指针
- 垃圾收集算法了解吗?
- 标记-清除算法:(产生内存碎片)
- 标记-复制算法:(保留一半空间用来复制,造成浪费)
- 标记-整理算法(相对比较慢)
- 三色标记算法了解吗?介绍一下。
优点:
- 用于垃圾回收器升级,将STW变为并发标记。STW就是在标记垃圾的时候,必须暂停程序,而使用并发标记,就是程序一边运行,一边标记垃圾;
- 避免重复扫描对象,提升标记阶段的效率。
什么是三色标记?
存在的问题:
- 浮动垃圾:在三色标记过程中,产生了新的垃圾。留给下一次GC去回收即可。
- 对象漏标:
- 说一下CMS收集器的垃圾收集过程。
- 初始标记:单线程运行,需要STW,标记GC Roots能直达的对象
- 并发标记:无停顿,和用户线程同时运行,从GC Roots直达对象开始便利整个对象图
- 重新标记:多线程运行,需要STW,标记并发阶段产生的对象
- 并发清除:无停顿,和用户线程同时运行,清理掉标记阶段标记的死亡对象
- G1垃圾收集器了解吗?
垃圾回收过程:
- 为什么要引入G1?
CMS的优点:
- 并发收集、低停顿
CMS的缺点:
- 导致内存碎片
- CMS的并发能力比较依赖CPU资源,并发回收时垃圾收集线程可能就抢占用户线程的资源,导致用户程序性能下降
- 你们项目中用到的什么垃圾收集器?为什么用?
ParNew(新生代) + CMS(老年代)
- 对象一定分配在堆中吗?
不一定。逃逸技术。
- 了解哪些JVM监控和故障处理工具?
JConsole
VisualVM
- JVM的常见参数配置知道哪些?
- 有做过JVM调优吗?
- 线上服务CPU占用过高怎么排查?
- top
- 内存飙升问题怎么排查?
- jmap+dump文件分析
- 频繁minor gc怎么解决?
- 频繁full gc怎么解决?
- 定位及解决OOM
原因:
- 一次性申请的太多:更改申请对象的数量
- 内存资源耗尽未释放:找到未释放的对象进行释放
- 本身资源不够:jmap -heap 查看堆信息
定位:
- 系统报OOM:提前设置报错时输出dump文件,根据dump文件来排查
- 系统还未OOM:导出dump文件来排查
- 线上JVM配置
[--add-opens=java.base/java.lang=ALL-UNNAMED, --add-opens=java.base/java.io=ALL-UNNAMED, --add-opens=java.base/java.util=ALL-UNNAMED, --add-opens=java.base/java.util.concurrent=ALL-UNNAMED, --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED, -Djava.util.logging.config.file=/home/appops/approot/conf/logging.properties, -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager, -Djava.awt.headless=true, -Xms3072m, -Xmx3072m, -XX:MetaspaceSize=256m, -XX:MaxMetaspaceSize=256m, -Dcom.netease.appname=nim-webserver, -verbose:gc, -verbose:class, -XX:+PrintGCDetails, -XX:+UseG1GC, -XX:MaxGCPauseMillis=100, -XX:+ParallelRefProcEnabled, --add-opens=java.base/java.lang=ALL-UNNAMED, --add-opens=java.base/java.io=ALL-UNNAMED, --add-opens=java.base/java.math=ALL-UNNAMED, --add-opens=java.base/java.net=ALL-UNNAMED, --add-opens=java.base/java.nio=ALL-UNNAMED, --add-opens=java.base/java.security=ALL-UNNAMED, --add-opens=java.base/java.text=ALL-UNNAMED, --add-opens=java.base/java.time=ALL-UNNAMED, --add-opens=java.base/java.util=ALL-UNNAMED, --add-opens=java.base/jdk.internal.access=ALL-UNNAMED, --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED, --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED, --add-opens=java.base/sun.net.util=ALL-UNNAMED, -Dio.netty.tryReflectionSetAccessible=true, -Xlog:gc:/home/appops/approot/logs/gc.log, -Djava.library.path=/home/appops/lib/, -Dforeign.domain=true, -Dorg.apache.catalina.SESSION_COOKIE_NAME=NTESwebSI, -Dsun.rmi.transport.tcp.responseTimeout=20000, -Dsun.rmi.dgc.client.gcInterval=7200000, -Dsun.rmi.dgc.server.gcInterval=7200000, -Dcom.sun.management.jmxremote, -Dcom.sun.management.jmxremote.ssl=false, -Dcom.sun.management.jmxremote.authenticate=false, -Dlog.dir=/home/appops/approot/logs, -XX:+UseG1GC, -Xlog:gc*:/home/appops/approot/logs/gc.log:time,tags,level, -Ddisconf.conf_server_host=imconf-jd.nim.service.163.org, -Ddisconf.version=RELEASE, -Ddisconf.app=nim_online, -Ddisconf.env=WebServer-Online-Music, -Dnim.logPath=/home/appops/approot/logs, -javaagent:/home/appops/webroot/WEB-INF/classes/sentry-javaagent-home/sentry-javaagent-premain-2.0.0.jar, -Dsentry_collector_libpath=/home/appops/webroot/WEB-INF/lib, -Djdk.tls.ephemeralDHKeySize=2048, -Djava.protocol.handler.pkgs=org.apache.catalina.webresources, -Dorg.apache.catalina.security.SecurityListener.UMASK=0022, -Dignore.endorsed.dirs=, -Dcatalina.base=/home/appops/approot, -Dcatalina.home=/home/appops/approot, -Djava.io.tmpdir=/home/appops/approot/tmp]
[-Dlog.dir=/home/appops/approot/logs, -Xms4096m, -Xmx4096m, -XX:MetaspaceSize=512m, -XX:MaxMetaspaceSize=512m, -verbose:gc, -XX:+PrintGCDetails, -Dcom.sun.management.jmxremote, -Dcom.sun.management.jmxremote.ssl=false, -Dcom.sun.management.jmxremote.authenticate=false, -Dcom.netease.appname=biz-experiment-api, -Xdebug, -Xrunjdwp:transport=dt_socket,address={{xdebug_address}},server=y,suspend=n, -Dserver.port=10001, -javaagent:/home/appops/approot/conf/sentry-javaagent-home/sentry-javaagent-premain-2.1.0.jar, -Dsentry_collector_libpath=/home/appops/approot/lib]
原文地址:https://blog.csdn.net/weixin_44804108/article/details/142485763
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!