得物Java开发面试题

1. Java类加载,如何打破双亲委派?

  • 创建自定义类加载器:创建一个新的类加载器类,继承自 ClassLoader 或其任何已有的子类。

  • 重写 loadClass 方法:在你的自定义类加载器中重写 loadClass 方法。

  • 加载类数据:在 loadClass 方法中,首先尝试使用当前类加载器来加载类数据。你可以从文件系统、网络或其他源获取类的二进制数据。

  • 定义类:如果在步骤 3 中成功加载了类的数据,使用 defineClass 方法将二进制数据转换为 Class<?> 对象。

  • 委派给父类加载器:如果步骤 3 和 4 失败,作为回退机制,将加载任务委派给父类加载器。

  • 测试自定义类加载器:创建一个测试程序,使用你的自定义类加载器来加载某个类,验证它是否可以正确地工作

2. 线程池使用场景,参数

可以复用线程,减少线程创建和销毁的开销。应用场景

  • Web 服务器:用于处理高并发的 HTTP 请求。
  • 大数据处理:用于并行处理大量的数据,例如 MapReduce。
  • 实时应用:在实时应用中用于处理多用户的并行请求或操作。
  • 文件上传和下载:在文件上传和下载服务中,可以使用线程池来并行处理多个文件传输任务。
  • 后台任务执行:用于定时或周期性的执行后台任务,例如日志清理,数据同步等。

线程池参数:

  • corePoolSize

    • 描述:线程池的基本大小。
    • 作用:当线程池中的线程数少于 corePoolSize 时,即使线程是空闲的,也不会被销毁。
  • maximumPoolSize

    • 描述:线程池的最大线程数。
    • 作用:当线程池中的线程数超过 corePoolSize 并且队列已满时,线程池可以扩展到 maximumPoolSize。
  • workQueue

    • 描述:用于存放待处理的任务的队列。
    • 作用:当线程池中的线程数达到 corePoolSize 时,新的任务将被放在队列中等待。
  • threadFactory

    • 描述:用于创建新线程的工厂。
    • 作用:可以用来设置线程的名称,优先级等。
  • handler

    • 描述:拒绝策略,当线程池和队列都满了之后,用于处理新来的任务。
    • 常见策略:
      • ThreadPoolExecutor.AbortPolicy:直接抛出异常。
      • ThreadPoolExecutor.CallerRunsPolicy:将任务回退给调用者。
      • ThreadPoolExecutor.DiscardPolicy:忽略新来的任务。
      • ThreadPoolExecutor.DiscardOldestPolicy:抛弃队列中最老的任务。
  • keepAliveTime

    • 描述:空闲线程的保持时间。
    • 作用:当线程池中的线程数量超过 corePoolSize 时,多余的空闲线程将在等待新任务的时候最多保持 keepAliveTime 时间。
  • timeUnit

    • 描述:keepAliveTime 的时间单位

3. 线程池异常处理

  • 使用 Future:如果你通过 submit 方法提交任务(而不是 execute),你会得到一个 Future 对象,可以用它来捕获异常
  • 在任务内部捕获异常:你可以在每个任务内部捕获和处理异常
  • 使用 uncaughtExceptionHandler:你可以为线程池中的线程设置一个UncaughtExceptionHandler 来捕获未捕获的异常

有哪些异常:

  • RejectedExecutionException

    • 描述:当线程池已关闭或线程池和工作队列都已满时,尝试提交新任务将抛出此异常。
    • 解决方案:可以考虑调整线程池的大小或队列长度,或者更改拒绝策略来处理这种情况。
  • OutOfMemoryError

    • 描述:如果线程池中的线程数或队列大小配置得太大,或者任务创建了太多大对象,你可能会遇到内存溢出错误。
    • 解决方案:优化代码以减少内存使用,或增加JVM的最大堆大小。
  • NullPointerException

    • 描述:当尝试提交的任务为null时,将抛出此异常。
    • 解决方案:确保提交到线程池的任务不是null。
  • IllegalStateException

    • 描述:当线程池处于不正确的状态时(例如,尝试多次关闭线程池),可能会抛出此异常。
    • 解决方案:检查代码以确保线程池的正确使用。
  • RuntimeExceptionExecutionException

    • 描述:当任务抛出运行时异常时,如果你使用了 Future.get() 方法来获取结果,将包装为 ExecutionException 抛出。
    • 解决方案:捕获这些异常并适当处理

4. Redis 基本数据结构

  • 字符串(String):可以存储文本或二进制数据。

  • 哈希表(Hashes):存储字段和字段值的映射,适合用来存储对象。

  • 列表(Lists):有序的字符串列表,常用于实现队列。

  • 集合(Sets):无序的字符串集合,可以快速查找、添加、删除元素。

  • 有序集合(Sorted Sets):与集合类似,但每个元素都会关联一个分数,元素间有序。

  • 位图(Bitmaps):通过位操作来存储和查询数据。

  • 超日志(HyperLogLogs):用于统计唯一值的数量,但会有一定的误差。

  • 流(Streams):用于实现消息队列的功能,支持多个消费者。

5. 如何保证数据库缓存一致性

  • 事务性:尽可能将缓存操作和数据库操作包含在一个事务中,这样可以确保要么都成功,要么都失败。
  • 使用队列:使用消息队列来缓冲数据库的写操作,并按顺序处理它们,以保证缓存和数据库的一致性。
  • 一致性哈希:在分布式缓存场景中,可以使用一致性哈希来保证数据的一致性。
  • 数据库触发器:利用数据库触发器,在数据变更时自动更新或清除缓存。

6. mysql底层数据结构,为什么选用B+树?

  • 磁盘I/O效率

    • 数据块的读写:B+树将数据存储在叶子节点,而非叶子节点仅存储键值和指向孩子节点的指针。这意味着磁盘I/O操作通常能够一次读取更多的数据。
    • 顺序扫描优化:B+树的叶子节点之间通过指针相连,这为范围查询和顺序扫描提供了高效的路径,减少了磁盘I/O次数。
  • 空间使用效率

    • 空间局部性:B+树的层级更少,更多的节点可以被加载到内存中,这提高了空间局部性和缓存命中率。
    • 节约空间:由于B+树的内部节点不存储数据,这可以更有效地利用空间来存储索引信息,从而节约存储空间。
  • 查询效率

    • 查询时间可预测:B+树保证了所有叶子节点都在同一层,这使得所有的查找操作路径长度相等,提供了可预测的查询时间。
    • 范围查询优势:通过顺序访问叶子节点,可以更快地完成范围查询。
  • 插入和删除操作效率

    • 高效的插入和删除:B+树提供了高效的插入和删除操作,因为它只需在叶子节点进行修改,而不需要频繁地重新平衡树结构。
  • 支持事务和并发控制

    • 易于实现锁机制:B+树结构便于实现各种锁机制(如行锁),这对于支持事务和并发控制是非常重要的

7.幻读了解吗?

幻读(Phantom Reads)是数据库事务管理中的一个概念,是一种并发控制现象。在一个事务的执行过程中,如果由于另一个事务的插入或删除操作,导致第一个事务重新执行一个相同的查询时返回的结果集不同,那么就出现了幻读

幻读通常可以通过使用更高级别的事务隔离来避免比如可串行化(Serializable)隔离级别。在此级别,事务是完全隔离的,意味着在一个事务开始到结束的过程中,不会看到其他事务所做的任何修改。

8.索引什么情况下索引会失效?

  • 不使用索引列的前缀

    • 如果查询条件没有包括索引的前缀列(即索引中的第一列),索引可能不会被使用。
  • 使用函数或表达式

    • 当在查询条件中对索引列使用函数、表达式、类型转换等操作时,索引可能不会被使用。例如,WHERE UPPER(column) = 'VALUE'
  • 使用通配符前缀

    • 当查询条件中使用通配符前缀(如 %value)时,索引可能不会被使用,因为通配符前缀无法利用索引的有序性。
  • 对列进行计算

    • 如果查询中对索引列进行计算或运算,索引可能会失效。例如,WHERE column * 2 = 10
  • 不等于(!=)操作符

    • 在某些情况下,使用不等于操作符(!=<>)可能导致索引失效,因为它不适用于某些类型的索引优化。
  • OR条件

    • 使用OR条件连接多个不同的索引列时,优化器可能无法有效地使用索引

9.线程安全,如何实现?

  • 互斥锁

    • 使用互斥锁(Mutex)或信号量来保护共享资源,确保一次只有一个线程可以访问它。
    • Java中的 synchronized 关键字和 ReentrantLock 类可以用来创建互斥锁。
  • 原子操作

    • 利用原子操作来执行多个步骤的操作,确保它们在多线程环境下是不可中断的。
    • 在Java中,可以使用 java.util.concurrent.atomic 包中的原子类(如 AtomicIntegerAtomicLong)来实现原子操作。
  • 线程安全的数据结构

    • 使用线程安全的数据结构,如 ConcurrentHashMapCopyOnWriteArrayList 等,来代替传统的集合类。
    • 这些数据结构内部使用了锁或其他机制来确保线程安全。
  • 不可变对象

    • 设计不可变对象,这些对象在创建后不能被修改,因此可以被多个线程安全地共享。
    • 使用 final 关键字来标记字段,确保它们不可变。
  • 线程局部存储

    • 使用线程局部存储(Thread-Local Storage,TLS)来为每个线程提供独立的变量副本,从而避免竞争条件。
    • 在Java中,可以使用 ThreadLocal 类来管理线程局部变量

10. 负载均衡算法?

(1)RandomLoadBalance:根据权重随机选择(对加权随机算法的实现)。这是Dubbo默认采用的一种负载均衡策略。
(2)LeastActiveLoadBalance:最小活跃数负载均衡。
Dubbo 就认为谁的活跃数越少,谁的处理速度就越快,性能也越好,这样的话,我就优先把请求给活跃数少的服务提供者处理。

(3)ConsistentHashLoadBalance:一致性Hash负载均衡策略。
ConsistentHashLoadBalance 中没有权重的概念,具体是哪个服务提供者处理请求是由你的请求的参数决定的,也就是说相同参数的请求总是发到同一个服务提供者。另外,Dubbo 为了避免数据倾斜问题(节点不够分散,大量请求落到同一节点),还引入了虚拟节点的概念。通过虚拟节点可以让节点更加分散,有效均衡各个节点的请求量。

(4)RoundRobinLoadBalance:加权轮询负载均衡。
轮询就是把请求依次分配给每个服务提供者。加权轮询就是在轮询的基础上,让更多的请求落到权重更大的服务提供者上。

11. java设计模式了解过哪些?


12. spring循环依赖,为什么需要三级缓存,两级缓存不行吗

Spring的三级缓存是为了解决循环依赖问题而引入的。在Spring容器中,如果两个Bean相互依赖,那么在创建Bean时就会出现循环依赖问题。为了解决这个问题,Spring使用了三级缓存1。

三级缓存包括:

  • singletonObjects: 一级缓存,存储单例对象,Bean已经实例化并初始化完成。
  • earlySingletonObjects: 二级缓存,存储singletonObject,这个Bean实例化了,但还没有初始化。
  • singletonFactories: 三级缓存,存储singletonFactory。

当一个Bean被创建时,Spring会首先从一级缓存中获取Bean实例。如果一级缓存中不存在该Bean实例,则Spring会从二级缓存中获取该Bean实例。如果二级缓存中也不存在该Bean实例,则Spring会从三级缓存中获取该Bean实例的工厂对象,并调用工厂方法创建该Bean实例。

13. tcp粘包和拆包
14. CP和AP的区别
 15. Java线程通信方式?
 16. CMS和C1区别?


 17. JVM调优的手段?

  • 调整JVM参数:例如,可以设置堆大小、新生代比例、GC算法等参数,以及启用垃圾回收器的Ergonomics机制。
  • 分析和定位当前系统的瓶颈:对于JVM的核心指标,我们的关注点和常用工具如下:

        CPU指标
        JVM内存指标
        JVM GC指标

  • 选择合适的GC收集器:串行收集器、并行收集器、并发收集器。
  • 架构调优和代码调优:架构调优是对系统影响最大的。性能调优基本上按照以下步骤进行:明确优化目标、发现性能瓶颈、性能调优、通过监控及数据统计工具获得数据、确认是否达到目标

18. 新生代频繁Minor GC原因,解决办法?

  • 新生代空间设置过大:如果新生代空间设置过大,会导致每次Minor GC的时间变长,从而影响系统的性能。因此,需要根据应用程序的实际情况来调整新生代的大小。
  • 对象引用链较长:如果对象引用链较长,进行可达性分析时间较长,也会导致Minor GC的频繁发生。因此,需要尽量减少使用全局变量和大对象。
  • 新生代survivor区设置的比较小:如果新生代survivor区设置的比较小,清理后剩余的对象不能装进去需要移动到老年代,造成移动开销。因此,需要根据应用程序的实际情况来调整survivor区的大小。

19. 频繁Full GC(老年代GC)的原因?解决办法(参考17)?

  • System.gc()方法的调用:虽然只是建议而非一定,但很多情况下它会触发Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+DisableExplicitGC来禁止RMI调用System.gc。
  • 老年代空间不足:老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象。为避免此种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
  • 永生区空间不足:当系统中要加载的类、反射的类和调用的方法较多时,永生区可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
  • CMS GC时出现promotion failed和concurrent mode failure:对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。措施为:增大survivor space、老年代空间或调低触发并发GC的比率。
  • 统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间:这是一个较为复杂的触发情况。Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。

20. Java内存区域,内存模型?
21. Java运行一个程序的过程?
22. 静态变量在什么阶段分配内存?
23. TCP和UDP的原理区别

  • TCP是面向连接的,UDP是无连接的
  • TCP是可靠的,UDP是不可靠的
  • TCP是面向字节流的,UDP是面向数据报文的
  • TCP只支持点对点通信,UDP支持一对一,一对多,多对多
  • TCP报文首部20个字节,UDP首部8个字节
  • TCP有拥塞控制机制,UDP没有
  • TCP协议下双方发送接受缓冲区都有,UDP并无实际意义上的发送缓冲区,但是存在接受缓冲区
     

24. 平时用SpringBoot经常会用注解,注解开发是怎么实现的?你提到了AOP,AOP和OOP是什么关系呢?

  • Spring Boot中的注解开发是通过Java的反射机制实现的。
  •  AOP与OOP(Object Oriented Programming)是面向不同领域的两种设计思想。OOP针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果

25. Java默认的垃圾收集器是哪个?GC的过程是由谁来调度的?GC线程是谁启动的?

  • Java默认的垃圾收集器是 G1 垃圾收集器
  • Java的垃圾收集过程是由 JVM 来调度的。JVM会在程序运行时,根据内存使用情况自动触发垃圾回收
  • GC线程是由 JVM 启动的。在JVM启动时,会启动一个或多个GC线程,用于执行垃圾回收

26. 平时使用MySQL增加索引可以提高查询效率,如何理解?

27. 查询第50条到100条记录

在SQL中,可以使用 LIMIT 和 OFFSET 子句来查询指定范围内的记录。假设你要查询第50条到100条记录,可以使用以下语句:

SELECT * FROM table_name LIMIT 50, 50;

28.InnoDB的索引类型

29. 主键索引、唯一索引和联合索引

  • 在MySQL中,主键索引是一种特殊的唯一索引,用于标识一条记录。主键索引的值必须唯一,且不能为NULL。如果表中没有定义主键,MySQL会自动创建一个名为PRIMARY的主键索引
  • 唯一索引是指索引列的值必须唯一,但是可以为NULL。如果一个表中有多个唯一索引,那么每个唯一索引都可以保证索引列的值唯一.
  • 联合索引是指将多个列组合在一起创建的索引。联合索引可以包含多个列,但是要注意,联合索引的顺序非常重要。如果查询条件中只涉及到联合索引中的第一个或前几个列,则该查询可以使用联合索引进行优化;否则,该查询无法使用联合索引进行优化

30. 一张表用a,b,c三个字段作为联合索引,一条SQL命中了a和b是否会走索引

在MySQL中,如果一张表使用a,b,c三个字段作为联合索引,一条SQL命中了a和b,那么这条SQL会走索引。但是,如果SQL命中了a和c或者b和c,则不会走索引

31. mysql的事务特性、隔离级别

  • 读未提交 (READ UNCOMMITTED)

在这个隔离级别中,一个事务可以读取另一个未提交事务的修改。
问题:这种级别可能会导致"脏读",即一个事务读取到另一个事务还未提交的数据,如果那个事务最终回滚,那么读取的数据就是无效的。
这是最低的隔离级别,锁定的需求最少。

  • 读提交 (READ COMMITTED)

在这个隔离级别中,一个事务只能读取其他事务已经提交的修改。
问题:尽管可以避免"脏读",但是可能会发生"不可重复读",即在同一个事务中,后续的查询可能会看到前一个查询中未看到的行或列的不同值。
这是大多数数据库系统的默认隔离级别。

  • 可重复读 (REPEATABLE READ)

在这个隔离级别中,其他事务不能在事务执行期间插入新行,从而防止了"幻读"。
问题:该隔离级别可以避免"脏读"和"不可重复读",但是可能会导致"幻读"。"幻读"是指当某个事务在读取某个范围内的所有行时,另一个事务又在该范围内插入了新行,导致前一个事务再次读取时看到了额外的、早先不存在的行。
在MySQL的InnoDB存储引擎中,这是默认的隔离级别。

  • 串行化 (SERIALIZABLE)

这是最严格的隔离级别。当一个事务选择了该隔离级别后,其他事务就不能并发执行,它们必须等待该事务完成。
问题:这种级别可以避免"脏读"、"不可重复读"和"幻读",但是性能开销最大,因为事务之间完全是串行执行的。

32. mysql的锁机制,悲观锁和乐观锁的区别
33. 讲一下collection和map
34. list和set有什么区别?set里面可以有null值吗?list是不是可以有多个null值?
35. hashmap和hashtable有什么区别?hashmap的底层原理?如何解决hash冲突?

36. concurrentHashMap和hashmap有什么区别?

  • 线程安全性:HashMap是线程不安全的,当出现多线程操作时,会出现安全隐患;而ConcurrentHashMap是线程安全的。
  • 并发操作:HashMap不支持并发操作,没有同步方法;ConcurrentHashMap支持并发操作。
  • 锁机制:ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,每个小的片段segment上面都有锁存在,这样只要保证每个Segment是线程安全的,也就实现了全局的线程安全。而HashMap没有采用锁分段技术

37. IOC和AOP的概念、IOC的实现机制即依赖注入的方式

38.spring bean 的生命周期

Bean 的生命周期指的是 Bean 在 Spring(IoC)中从创建到销毁的整个过程。Bean 的生命周期主要包含以下 5 个流程:

(1)实例化:为 Bean 分配内存空间;

(2)设置属性:将当前类依赖的 Bean 属性,进行注入和装配;

(3)初始化:

执行各种通知。
执行初始化的前置方法。
执行初始化方法。
执行初始化的后置方法。
(4)使用 Bean:在程序中使用 Bean 对象;

(5)销毁 Bean:将 Bean 对象进行销毁操作。

39. springboot配置文件的加载顺序?yml和properties

在 Spring Boot 中,当同时存在 .properties 和 .yml 配置文件时,Spring Boot 会优先使用 yaml 格式的配置文件,而 properties 格式的配置文件时使用 

在加载配置文件时,Spring Boot 会按照以下顺序加载:

  • 优先加载 application.yml 或者 application.properties 文件。
  • 其次加载 classpath:/config/application.yml 或者 classpath:/config/application.properties 文件。
  • 最后加载 classpath:/application.yml 或者 classpath:/application.properties 文件。
  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金州饿霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值