• Java常见面试题


    1、mysql并发事务会带来哪些问题,如何解决?

    MySQL的并发事务可能会带来以下几个主要问题:

    脏读(Dirty Read):当一个事务读取另一个未提交的事务的数据时,可能会读取到不一致的数据。
    不可重复读(Non-repeatable Read):当一个事务在多次读取同一数据时,可能会因为另一个并发的事务修改了数据而导致读取到的结果不一致。
    幻读(Phantom Read):当一个事务在多次读取某一范围的数据时,可能会因为另一个并发的事务插入了新的数据而导致读取到的结果不一致。
    死锁(Deadlock):当两个或更多的事务互相等待对方释放资源时,会导致事务无法继续执行。
    性能问题:高并发下,如果事务处理不当,可能会导致数据库性能下降,影响整个系统的性能。

    解决方案:

    脏读:可以通过设置事务的隔离级别为READ COMMITTED或更高级别来避免脏读。READ COMMITTED级别会确保只读取已经提交的事务的数据。
    不可重复读和幻读:可以通过设置事务的隔离级别为REPEATABLE READ或SERIALIZABLE来避免不可重复读和幻读。REPEATABLE READ级别会确保在一个事务内多次读取同一数据时,结果是一致的。SERIALIZABLE级别是最严格的隔离级别,会确保并发事务之间互不干扰。
    死锁:可以通过设置合适的锁策略和锁超时时间来避免死锁。例如,可以设置锁的获取顺序,避免循环等待;可以设置锁的超时时间,避免无限等待。
    性能问题:可以通过优化数据库设计、使用索引、减少锁的使用、使用乐观锁等方式来提高并发事务的性能。
    总的来说,正确地处理并发事务需要理解它们可能带来的问题,并根据具体的应用场景和需求选择合适的解决方案。

    2、请详细描述Redis持久化机制?

    Redis的持久化机制指的是将Redis内存中的数据保存到硬盘中,以便在服务器重启或者宕机后可以快速地恢复数据。

    Redis支持两种持久化方式:RDB(Redis DataBase)和AOF(Append Only File)。

    RDB持久化机制: 是在指定的时间间隔内生成数据集的快照(Snapshot)。RDB持久化可以在指定的时间间隔内生成数据快照,这个时间间隔通常可以由用户在配置文件中进行配置。当Redis需要持久化时,它会 fork 出一个子进程,子进程会将内存中的数据写入硬盘中的一个临时文件,当持久化过程完成后,子进程会退出。你可以在配置文件中通过设置rdb_save_time_interval参数来控制RDB快照的生成时间间隔。

    AOF持久化机制: 是记录Redis的所有写操作到磁盘中。当Redis重启时,可以通过执行AOF文件中的命令来恢复数据集。AOF持久化比RDB持久化更加实时,可以保证数据的实时备份和持久化。你可以在配置文件中通过设置aof_enabled参数来开启或关闭AOF持久化,aof_filename参数来指定AOF文件的名称,aof_interval参数来控制AOF文件的写入时间间隔,aof_no_checksum参数来禁用或启用AOF文件的checksum。

    在什么情况下选择使用RDB或AOF持久化,需要根据具体的使用场景和需求进行选择。如果你的应用需要备份大规模的数据,并且需要快速地恢复数据,那么RDB持久化可能更加适合。如果你的应用需要实时备份数据,并且需要持久化的数据比较小,那么AOF持久化可能更加适合。

    3、简述Redis缓存雪崩和缓存穿透的问题和解决方案?

    缓存雪崩: 是指当缓存中大量数据同时过期时,这些请求会同时转发到数据库,导致数据库压力突然增大,就像雪崩一样。这种情况通常是由于缓存策略不当所导致的,例如缓存时间设置相同或相近,导致缓存集体失效。

    缓存穿透: 是指查询一个不存在的key,由于缓存和数据库中都没有这个key,因此每次请求都会直接查询数据库,导致数据库压力增大。这种情况通常是由于恶意攻击或者数据一致性校验不严谨所导致的。

    方式解决:

    对应缓存雪崩:在缓存策略中引入随机过期时间,避免大量缓存同时失效。例如,在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
    使用互斥锁,当缓存失效时,不是立即查询数据库,而是先使用互斥锁等待一段时间,如果缓存在此期间被更新,则重新获取缓存数据;如果没有被更新,则再查询数据库。

    对于缓存穿透:使用布隆过滤器,将存储的数据放入布隆过滤器中,每次数据查询首先查询布隆过滤器,如果过滤器中判断存在,再到缓存查询,如果没有,再进入数据查询。这样能大大减轻数据库查询压力。
    缓存空对象,当数据库数据不存在时,将返回的空对象缓存起来,同时设置一个过期时间。这样在访问数据时,将从缓存中获取,从而保护了数据库。但要注意对空值设置过期时间,否则会出现数据更新后缓存数据未及时更新的问题。
    对热点数据进行永不过期处理,即不设置热点数据的过期时间。但这只适用于热点数据不会频繁更新的情况。

    4、RabbitMQ消息丢失及对应解决方案

    (1) RabbitMQ事务机制和confirm模式:

    生产者在发送数据之前开启RabbitMQ事务机制,如channel.txSelect,然后发送消息。如果消息没有成功被RabbitMQ接收到,那么生产者会收到异常报错,此时可以回滚事务channel.txRollback,然后重试发送消息。如果收到了消息,那么可以提交事务channel.txCommit。这种机制类似于数据库事务机制,可以保证消息的可靠性传输。另外,开启confirm模式,生产者每次写的消息都会分配一个唯一的ID,如果写入了RabbitMQ中,RabbitMQ会回传一个ack消息,告诉生产者这个消息已经收到,这样可以避免消息丢失。

    (2) Broker消息中间件自身丢失消息解决方案:

    创建队列时设置队列持久化。在创建队列时,将持久化参数设置为true,这样可以保证RabbitMQ持久化queue的元数据,即使是RabbitMQ自身出现问题,恢复之后也会自动读取之前存储的数据。
    设置消息的deliveryMode为2。在发送消息时,将deliveryMode设置为2,这样RabbitMQ会将消息持久化到磁盘上,即使RabbitMQ出现问题,再次重启后也会从磁盘上恢复queue和里面的数据。
    以上是关于RabbitMQ消息丢失及对应解决方案的相关内容,希望能对你有所帮助。

    5、什么叫线程安全?举例说明

    线程安全是指多线程环境下,一个对象或函数能够在多个线程同时访问的情况下,保证其行为的一致性和正确性。线程安全的主要目标是避免数据竞争和保证并发操作的正确性。

    例如,一个ArrayList类在添加一个元素时,可能有两步操作:一是在Items[Size]的位置存放此元素,二是增大Size的值。在单线程环境下,由于操作是顺序执行,所以没有问题。但是在多线程环境下,如果两个线程同时执行这两步操作,可能会产生问题。

    在这种情况下,一种解决方法是使用同步机制,例如synchronized关键字或者Lock对象,来确保在任何时刻只有一个线程可以执行ArrayList类的添加元素操作,这样就可以避免数据竞争和并发操作的错误。这就是线程安全的一种实现方式。

    6、举例说明常用的加密算法

    AES加密算法:全称Advanced Encryption Standard,也就是高级加密标准,这是一种被广泛使用的加密算法,可以有效保护敏感信息。
    RSA加密算法:这是一种非对称加密算法,使用公钥和私钥两个密钥,公钥用于加密数据,私钥用于解密数据,非常安全,广泛用于数据传输等场景。
    DES加密算法:全称Data Encryption Standard,也就是数据加密标准,这是一种对称加密算法,被广泛用于保护敏感信息,但由于其密钥长度较短,现在已经被认为不够安全。
    SHA-1和SHA-256加密算法:SHA是安全哈希算法,主要用于生成消息摘要,也就是将输入的数据通过哈希算法生成一个固定长度的字符串,无法逆向生成原始数据。SHA-1和SHA-256是SHA算法的不同版本,SHA-256因为其安全性更高而被更广泛使用。
    RSA-SHA256混合加密算法:这是一种将SHA-256和RSA两种算法结合使用的加密方式,先用RSA算法生成一个签名,然后用SHA-256对数据进行摘要处理,同时用RSA公钥对SHA-256生成的摘要进行加密,可以同时实现签名和加密双重保护。
    MD5加密算法:MD5的全称是Message-Digest Algorithm 5,它可以将任意长度的“字节串”变换成一个128位的大整数,并且它是一个不可逆的字符串变换算法。即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串。

    7、synchronized和ReentrantLock有什么区别?

    (1) 用法的不同:synchronized是Java语言内置的关键词,由Java语言自动支持;而ReentrantLock是java.util.concurrent.locks包中的类,需要手动创建对象进行使用。

    (2)锁的获取和释放:synchronized是隐式获取和释放锁,而ReentrantLock需要显式地调用方法来获取和释放锁。

    (3)线程中断响应:synchronized不支持线程中断,当线程处于synchronized块中时,不能响应中断;而ReentrantLock支持线程中断,可以在锁被持有期间响应中断。

    (4)锁的级别:synchronized是JVM级别的,而ReentrantLock是API级别的。synchronized是Java语言内置的,所有的Java代码都可以使用;而ReentrantLock需要手动实现,使用起来相对较复杂。

    (5)公平性:synchronized不具有公平性,无法保证锁的获取顺序;而ReentrantLock可以通过构造函数参数来设定公平性,有公平锁和非公平锁两种模式。

    (6)等待可中断性:synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁。

    (7)锁的底层实现:synchronized和ReentrantLock底层实现方式不同。synchronized是使用乐观并发策略实现的,而ReentrantLock是使用悲观并发策略实现的。

    参考:synchronized和ReentrantLock有什么区别

    8、synchronized和lock的区别

    区别:

    1.synchronized是关键字,Lock是接口;

    2.synchronized是隐式的加锁,lock是显式的加锁;

    3.synchronized可以作用于方法上,lock只能作用于方法块;

    4.synchronized底层采用的是objectMonitor,lock采用的AQS;

    5.synchronized是阻塞式加锁,lock是非阻塞式加锁支持可中断式加锁,支持超时时间的加锁;

    6.synchronized在进行加锁解锁时,只有一个同步队列和一个等待队列, lock有一个同步队列,可以有多个等待队列;

    7.synchronized只支持非公平锁,lock支持非公平锁和公平锁;

    8.synchronized使用了object类的wait和notify进行等待和唤醒, lock使用了condition接口进行等待和唤醒(await和signal);

    9.lock支持个性化定制, 使用了模板方法模式,可以自行实现lock方法;

    参考:synchronized和lock的区别

    9、如何保证接口的幂等性

    幂等性:指的是同一操作执行多次时,结果是相同的,不会产生副作用或重复操作。

    • 在接口中添加幂等性检查逻辑。例如,对于更新操作,可以在接口中检查传入的参数是否与当前资源的状态一致,如果不一致则返回错误。
    • 使用乐观锁或者悲观锁来防止并发操作导致的问题。乐观锁通过在数据行中添加一个版本号来实现,每次更新都会增加版本号。悲观锁则是通过锁定数据行来实现,只有一个线程可以执行更新操作。
    • 在数据库层面保证幂等性。例如,使用数据库的唯一约束来保证创建操作的幂等性。
    • 使用令牌桶或者漏桶算法限制接口的调用频率,防止由于客户端的重复请求导致的问题。
    • 对于需要多次请求的操作,可以使用分布式事务来保证操作的原子性。

    参考:怎么保证 java 语言接口的幂等性?

    10、什么是分布式事务,如何解决

    分布式事务:在分布式系统中一次操作需要由多个服务协同完成,这种由不同的服务之间通过网络协同完成的事务称为分布式事务。例如:小明给张三转账100,A服务器上要先去A数据库扣100,然后B服务器上B数据库加100,两个操作要么都成功,要么都失败。

    常见的分布式事务解决有:TCC、本地事务表、MQ事务消息等。

    参考:七种常见分布式事务详解

    11、HashMap的结构和原理是什么

    HashMap 基于 Map 接口实现,元素以键值对的方式存储,并且允许使用null建和null值,因为key不允许重复,因此只能有一个键为 null,另外 HashMap 不能保证放入元素的顺序,它是无序的,和放入的顺序并不能相同。HashMap是线程不安全的。

    jdk1.7 底层实现是 数组 + 链表

    jdk1.8 底层实现是 数组+链表+红黑树 。如果哈希表单向链表中元素超过8个,那么单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。

    参考:HashMap底层实现原理解析

    12、CurrentHashMap是如何保证线程安全的

    锁分段技术:HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,同个对象锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。ConcurrentHashMap使用分段锁Segment来保护不同段的数据,Segment继承ReentrantLock实现锁的功能。

    参考:java——CurrentHashMap

    ConcurrentHashMap是如何保证线程安全的

    13、java线程池有哪些参数,都有什么含义

    参考:线程池七大参数

    14、java 中的volatile关键字是干嘛的

    在 Java 中,volatile 是一个关键字,用于声明变量。volatile 变量的作用是确保被声明的变量在多个线程之间的可见性、有序性和禁止重排序,从而实现线程安全的操作。

    具体来说,当一个变量被声明为 volatile 时,volatile 变量的写操作会立即刷新到主内存,而读操作会从主内存中读取最新值,而非从本地线程缓存中读取。

    需要注意的是,虽然 volatile 变量可以保证可见性和禁止指令重排,但它并不能保证线程安全,因为它只保证了可见性和有序性,而不保证原子性。对于一些需要多个操作才能完成的操作,比如 i++ 这样的自增操作,就不能简单地使用 volatile关键字来保证线程安全,需要使用更为严格的同步机制,比如synchronized 关键字或 Lock 接口。

    15、java中垃圾收集的方法有哪些

    (1)、标记-清除

    这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:1.效率不高,标记和清除的效率都很低;2.会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。

    (2)、复制算法

    为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。 于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)

    (3)、标记-整理

    该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候现将可回收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了。

    (4)、分代收集

    现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除。

    参考:堆内存分配及回收策略

    16、什么是类加载器,类加载器有哪些

    类加载器是实现通过类的权限定名获取该类的二进制字节流的代码块。在Java中,类加载器主要有四种类型:

    • 启动类加载器:负责加载Java核心类库,无法被Java程序直接引用。
    • 扩展类加载器:类似于加载Java的扩展库,Java虚拟机提供一个扩展库目录,该类加载器在此目录里面查找并加载Java类。
    • 系统类加载器:根据Java应用的类路径来加载Java类,主要是加载自己写的那些类,可以通过ClassLoader.getSystemClassLoader()来获取它。
    • 自定义加载器:用户自己定义的类加载器。

    17、什么是双亲委派

    双亲委派(双亲优先)是Java类加载器的一种工作机制,用于保护Java程序的安全性和稳定性。

    根据双亲委派模型,当一个类加载器需要加载某个类时,它首先将这个任务委派给它的父类加载器,只有当父加载器无法加载时,才由该加载器自己尝试加载。如果都无法加载,会委派给引导类加载器(Bootstrap Class Loader)进行加载。

    双亲委派的好处在于,它能够保证Java虚拟机中的类的一致性和安全性,避免了不同类加载器之间可能出现的冲突和错误。同时,双亲委派模型也提高了Java虚拟机的性能和效率,因为它避免了不必要的类加载和重复加载。

    18、抽象类和接口有什么区别

    • 定义:抽象类是一个类,可以有普通方法和抽象方法,其中抽象方法必须被子类实现;接口是一组抽象方法的集合,所有方法都是抽象方法,且没有具体实现。

    • 实现:子类只能继承一个抽象类,但可以实现多个接口。

    • 构造函数:抽象类可以有构造函数,接口没有构造函数。

    • 变量:抽象类可以有变量,接口只能定义常量。

    • 访问控制:抽象类中的方法可以是public、protected和default访问控制,而接口中的方法默认是public。

    • 默认实现:抽象类可以有普通方法的默认实现,而接口中所有的方法都没有默认实现。

    • 继承:子类继承抽象类时必须实现其中的抽象方法,否则该子类也必须是抽象类;子类实现接口时必须实现其中的所有方法。

    抽象类是对类抽象,接口是对行为抽象。如果一个类具有一些共同的属性和行为,那么可以将这些共同的属性和行为放到抽象类中,让子类继承并实现其中的抽象方法。如果一个类只是具有一些共同的行为,那么可以将这些共同的行为定义到接口中,让实现该接口的类来实现其中的方法。

    19、如何解决缓存和数据库双写数据一致性问题

    每次读取数据:
    如果读缓存里的数据,直接读缓存的;
    如果缓存里有数据读不到 ,则从数据库里面读数据,并将数据更新到缓存;
    将读取到的数据塞入到缓存中,下次读取时,就可以直接命中。
    再来看一下写请求,规则是“先更新 db,再删除缓存”,详细步骤如下:

    更新数据:
    先更新数据库的数据,再删除缓存的数据;

    极端情况的问题:

    上面的这种策略在极端情况下也会存在并发问题么,只不过概率比较小,比如:

    (1) 缓存刚好失效
    (2) 请求 A 读取数据,缓存里没读取到,然后从数据库读取,得一个 a 值,并开始将 a 更新到缓存,但因为网络问题一直阻塞
    (3) 请求 B 更新数据,将新值 b 写入数据库,然后删除缓存里的数据
    (4) 此时 A 网络变好,不再阻塞,将 a 更新到了缓存
    (5) 此时数据库里是 b ,而缓存里是 a ,就不一致了

    如果对数据一致性和实时性要求比较高的话,可以基于消息队列的重试机制。具体来说,就是把操作缓存,或者操作数据库的请求暂存到队列中,通过消费队列来重新处理这些请求,因此上面的问题可以把所有更新缓存和删除缓存的操作加入到消息队列里,消息队列可以保证其有序的执行。

    因此上面极端情况的解决方式:
    (1) 缓存刚好失效
    (2) 请求 A 读取数据,缓存里没读取到,然后从数据库读取,得一个 a 值,把 a 更新到缓存的这步操作加入到消息队列 Q 中
    (3) 请求 B 更新数据,将新值 b 写入数据库,把从缓存里删除数据这步操作加入到消息队列 Q 中
    (4) 消息队列 Q中将安装放入队列的顺序依次执行,从而确保一致性;

    20、Arrays中sort排序运用了哪几种排序方式

    (1)如果数组元素个数小于47,那么使用改进的插入排序进行排序,
    (2)如果元素个数大于插入排序的阈值并且小于快速排序的阈值 286,则使用改进的双轴快速排序进行排序,
    (3)如果元素个数大于快速排序的阈值,根据数组的无序程度来判定继续使用哪种算法,无序程度通过将数组划分为不同的有序序列的个数来判定,如果有序序列的个数大于 67,则认为原数组基本无序,则仍然使用双轴快速排序,如果小于MAX_RUN_COUNT,则认为原数组基本有序,使用归并排序进行排序。

    Arrays中sort方法的黑科技

    21、怎么判断一个对象能不能回收(如何判断对象“已死”)

    引用计数法
    对象持有一个引用计数器,当对象被引用时+1,当引用失效时-1,任何时刻对象引用计数器的值为0时,对象被认定为不可使用状态。 优点:原理简单。判定效率高 缺点:对象之间互相引用,会导致对象的引用计数器一直不为0,从而永远不被认定为不可使用状态。

    可达性分析算法
    首先会有一个 称之为“GC ROOT”的根对象作为起点,我们创建的对象的引用都会链接到“GC ROOT”上,可以想象下,这就是一棵树,“GC ROOT”就是树顶,创建对象的引用根据引用关系在下面开枝散叶。当引用对象到“GC ROOT"之间的引用链断开时,说明该对象不可达,即认定为不可被使用状态。

    JVM的垃圾回收过程

    22、Java对象一定是在堆上进行分配的吗

    不一定,有可能在栈上分配。
    对象栈上分配:我们通过JVM内存分配可以知道JAVA中的对象都是在堆上进行分配,当对象没有被引用的时候,需要依靠GC进行回收内存,如果对象数量较多的时候,会给GC带来较大压力,也间接影响了应用的性能。为了减少临时对象在堆内分配的数量,JVM通过逃逸分析确定该对象不会被外部访问。如果不会逃逸可以将该对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。

    **对象逃逸分析:**就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。

    参考:Java对象一定是在堆上进行分配的吗?

    23、HashMap是怎么解决哈希冲突的

    通常解决hash冲突的方法有 4 种:
    (1)开放定址法,也称为线性探测法,就是从发生冲突的那个位置开始,按照一定的次序从hash表中找到一个空闲的位置,然后把发生冲突的元素存入到这个空闲位置中。ThreadLocal就用到了线性探测法来解决hash冲突的。

    (2)链式寻址法,这是一种非常常见的方法,简单理解就是把存在hash冲突的key,以单向链表的方式来存储,比如HashMap就是采用链式寻址法来实现的。

    (3)再hash法,就是当通过某个hash函数计算的key存在冲突时,再用另外一个hash函数对这个key做hash,一直运算直到不再产生冲突。这种方式会增加计算时间,性能影响较大。

    (4)建立公共溢出区, 就是把hash表分为基本表和溢出表两个部分,凡是存在冲突的元素,一律放入到溢出表中。

    HashMap在JDK1.8版本中,通过链式寻址法+红黑树的方式来解决hash冲突问题,其中红黑树是为了优化Hash表链表过长导致时间复杂度增加的问题。当链表长度大于8并且hash表的容量大于64的时候,再向链表中添加元素就会触发转化。

    参考:HashMap是怎么解决哈希冲突的

    24、Minor GC和Full GC的区别

    **Minor GC :**又称为新生代 GC ,指的是发生在新生代的垃圾收集。因为 Java对 象大多都具备朝生夕灭的特 性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。

    **Full GC :**又称为 老年代 GC 或者 Major GC ,指发生在老年代的垃圾收集。出现了 Major GC ,经常会伴随 至少一次的Minor GC (并非绝对,在 Parallel Scavenge 收集器中就有直接进行 Full GC 的策略选择过程)。 Major GC 的速度一般会比Minor GC 慢 10 倍以上。老年代:标记-整理算法(清理的时候做内存移动)

    25、static加载顺序

    (1)含有static的静态代码块和类变量先执行,执行一次之后就不再需要加载,静态代码块和类变量没有特定的先后顺序,按照代码顺序执行

    (2)如果类之间存在继承关系,先加载父,在加载子的内容

    (3)单独一个类的加载顺序应该是,静态代码块(类变量)--------成员变量-----------构造方法

    参考:java static加载顺序

    26、其他知识点学习

    一文搞定Redis分布式锁的实现和原理
    MySQL索引从基础到原理,看这一篇就够了
    可重入锁和不可重入锁的区别
    MySQL的间隙锁
    MySQL事务隔离级别详解
    JVM的垃圾回收过程
    如何破坏双亲委派模型
    jvm有哪些垃圾回收器
    一文读懂Java类加载全过程
    常见的排序算法及其复杂度分析

    27、其他常见面试题

    (1)Java面试题及答案整理

    (2)JAVA 面试题经典

    (3)Java面试题及答案整理

    (4)史上最全Java面试题

    (5)技术面试题–java基础

    (6)我掏空了各大搜索引擎,给你整理了199道Java面试题,满满干货记得收藏

    (7)Java 面试知识

    (8)21道Java基础大厂面试题汇总

    (9)大厂面试题系列

    (10)MySQL必看15道面试题

  • 相关阅读:
    HTML + CSS 实现矩形/圆形进度条效果 - SVG
    【C++】继承 ⑦ ( 继承中的对象模型分析 | 继承中的构造函数和析构函数 )
    协程学习(一)--初识协程
    【EI会议征稿】第二届可再生能源与电气科技国际学术会议(ICREET 2023)
    如何在Android项目中制作和使用三方包(jar文件)
    Vue3学习
    通过IIS部署Flask项目
    HiveQL
    (Python)MATLAB mat矩阵和Python npy矩阵转换
    9.Eureka服务发现+Ribbon+RestTemplate服务调用
  • 原文地址:https://blog.csdn.net/qq_33697094/article/details/132948255