volatile关键词的作用是什么适用于多线程环境，限制代码重排序优化，提供可见性保证。不保证原子性，不能替代锁。volatile如何保证线间可见和避免指今重排可见性：对于被声明为 volatile 的变量，在一个线程中的写操作会立即刷新到主内存，同时，其他线程读取该变量时会从主内存中获取最新的值。这样可以确保对该变量的修改对其他线程是可见的，避免了线程之间的数据不一致性。禁止指令重排序：volatile 关键字禁止编译器和处理器对被修饰变量相关指令进行重排序优化。这样可以确保在多线程环境下，程序的执行顺序与程序员编写的顺序保持一致，避免了可能导致并发问题的指令重排序。创建线程的几种方式继承Thread类并重写run方法，然后通过创建该类的实例来启动线程。实现Runnable接口并实现run方法，然后通过创建Thread对象，将Runnable实例作为参数传递给Thread，并调用start()方法启动线程。使用线程池来管理和复用线程，可以通过Executors类的工厂方法创建不同类型的线程池。通过将Runnable或Callable实例提交给线程池，线程池会自动调度和执行任务。调用start方法和调用run方法的区别start是启动线程的方法，run是线程中方法的具体实现，如果直接调用run方法他不会创建一个新的线程线程的常用调度方法sleep 让当前线程休眠指定的毫秒数。yield 用于提高线程的执行效率，但不能保证一定会让出CPU。join 会阻塞当前线程，直到被调用的线程执行完毕后才会继续执行当前线程。wait notify notifyAll 这些方法用于实现线程间的协作和通信。interrupt 需要在线程的代码中通过检查中断标志位，并做相应处理来实现线程的中断。线程的状态有几种新建 New运行 Runnable阻塞 Blocked等待 Waiting超时等待 Timed Waiting终止 TerminatedThreadLocal本质是什么是一种线程封闭的机制，它是Java中的一个类，用于在多线程环境下为每个线程提供独立的变量副本，使得每个线程都可以访问自己独立的变量，互不干扰。使用他可能会造成内存泄露，所以要注意管理好变量的生命周期，确保在适当的时候进行清理和回收，以免造成资源浪费。ThreadLocal内存泄漏是什么引起的ThreadLocal内存泄漏通常由于线程池未正确清理或ThreadLocal对象生命周期过长。在使用ThreadLocal时，要及时清理ThreadLocal，特别是在使用线程池时，确保在线程执行前或执行后重置ThreadLocal，以避免内存泄漏。ThreadLocalMap的结构他是ThreadLocal类中的一个内部类，用于在多线程环境下为每个线程提供独立的变量副本。它是一个哈希表，使用ThreadLocal对象的弱引用作为key，存储线程独立的变量副本作为value。通过ThreadLocalMap，每个线程都可以独立地维护自己的变量副本，实现了线程级别的数据隔离。ThreadLocalMap使用开放地址法解决哈希冲突，并在扩容时进行再散列。为了避免内存泄漏，使用完ThreadLocal后，应该及时调用remove()方法清理当前线程的ThreadLocal副本。父子线程怎么共享数据通过在父线程和子线程之间使用共享变量来实现数据共享。使用ThreadLocal可以在父线程和子线程之间实现数据隔离，每个线程都有独立的变量副本。父线程设置ThreadLocal变量，子线程可以通过ThreadLocal访问和修改自己的副本。父线程和子线程可以通过线程通信机制，如wait/notify或者Lock/Condition来实现数据的交换和共享。使用线程池中的ThreadLocal：如果使用线程池创建线程，可以通过ThreadLocal在父线程和子线程之间传递数据。synchronized锁升级过程在没有竞争的情况线程可以直接访问不需要加锁，当有一个线程访问被synchronized修饰的代码块的时候jvm会给他上一个偏向锁，这个线程可以在未来的执行中直接获取锁，无需再进行同步操作，提高了单线程场景下的性能，当多线程尝试获取同一个锁时JVM会尝试将偏向锁升级为轻量锁，适用于锁竞争不激烈的情况，如果轻量锁尝试失败或者出现堵塞就会升级重度锁。synchronized锁优化synchronized锁的优化包括偏向锁、轻量级锁、自旋锁、锁消除和锁粗化。偏向锁适用于无竞争情况，轻量级锁适用于竞争不激烈的情况，自旋锁避免线程阻塞，锁消除消除不必要的锁开销，锁粗化合并连续的同步操作。synchronized锁消除这个是在jvm在运行的时候会进行逃逸分析的优化措施，当jvm发现这个代码不会被其他线程所访问的时候就会去自动消除synchronized锁，他在默认情况是开启的，可以配置JVM参数来关闭他。synchronized和ReetrantLock的区别synchronized是java中的关键字而ReetrantLock是JDK的API在1.6以后性能就都差不多了因为synchronized加入了适应性自旋、锁消除等CAS 呢？CAS 了解多少？他是一种并发控制机制，用于实现多线程环境下的原子操作。CAS操作涉及三个操作数：内存位置（或称为变量）、期望的旧值和新值。CAS操作会检查内存位置的值是否等于期望的旧值，如果相等，则将内存位置的值更新为新值；如果不相等，则说明其他线程已经修改了内存位置的值，CAS操作失败。CAS 有什么问题？如何解决？ABA 问题当多个线程在同一时间修改一个东西，比如一个数值，有时候会出现一个问题。想象你有一个数值是A，然后有一个人把它改成了B，又改回了A。如果另一个人要检查这个数值是不是A，他可能会发现是A，因为最后的状态是A。但实际上在中间有过变化。每次修改变量，都在这个变量的版本号上加 1，这样，刚刚 A->B->A，虽然 A 的值没变，但是它的版本号已经变了，再判断版本号就会发现此时的 A 已经被改过了。循环性能开销自旋 CAS，如果一直循环执行，一直不成功，会给 CPU 带来非常大的执行开销。可以限制自旋次数，超过就停止自旋只能保证一个变量的原子操作CAS 保证的是对一个变量执行操作的原子性，如果对多个变量操作时，CAS 目前无法直接保证操作的原子性的。可以考虑改用锁来保证操作的原子性可以考虑合并多个变量，将多个变量封装成一个对象，通过 AtomicReference 来保证原子性。原子操作类了解多少？Atomic 包里的类基本都是使用 Unsafe 实现的包装类。使用原子的方式更新基本类型，Atomic 包提供了以下 3 个类：AtomicBoolean：原子更新布尔类型。AtomicInteger：原子更新整型。AtomicLong：原子更新长整型。通过原子的方式更新数组里的某个元素，Atomic 包提供了以下 4 个类：AtomicIntegerArray：原子更新整型数组里的元素。AtomicLongArray：原子更新长整型数组里的元素。AtomicReferenceArray：原子更新引用类型数组里的元素。AtomicIntegerArray 类主要是提供原子的方式更新数组里的整型原子更新基本类型的 AtomicInteger，只能更新一个变量，如果要原子更新多个变量，就需要使用这个原子更新引用类型提供的类。Atomic 包提供了以下 3 个类：AtomicReference：原子更新引用类型。AtomicReferenceFieldUpdater：原子更新引用类型里的字段。AtomicMarkableReference：原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法是 AtomicMarkableReference（V initialRef，boolean initialMark）。如果需原子地更新某个类里的某个字段时，就需要使用原子更新字段类，Atomic 包提供了以下 3 个类进行原子字段更新：AtomicIntegerFieldUpdater：原子更新整型的字段的更新器。AtomicLongFieldUpdater：原子更新长整型字段的更新器。AtomicStampedReference：原子更新带有版本号的引用类型。该类将整数值与引用关联起来，可用于原子的更新数据和数据的版本号，可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。线程死锁了解吗？该如何避免？死锁是指两个或两个以上的线程在执行过程中，因争夺资源而造成的互相等待的现象，在无外力作用的情况下，这些线程会一直相互等待而无法继续运行下去。如果多个线程需要获取多个资源，可以按照相同的顺序获取，避免循环等待。可以在尝试获取资源时设置一个超时时间，如果在规定时间内没有获取到资源，就放弃或者尝试其他途径。将资源分为不同的级别，要求线程按照顺序获取资源，避免出现循环等待的情况。通过wait()和notify()等机制，让线程在获取不到资源时进入等待状态，等到资源释放时再被唤醒。什么是线程池？他可以帮我们管理线程避免线程的重复创建和销毁，可以重复利用线程ThreadPoolExecutor 的参数有哪些核心线程数最大线程数量线程存活时间存活时间单位工作队列线程工厂拒绝策略给线程池提交一个任务的流程是什么样子的当任务提交给线程池后会先判断是否小于核心线程数，如果小于就会直接创建线程，如果大于等于就会放到工作队列中，放到队列前会判断一下是否已满，如果没满就放到队列中，如果满了就会执行拒绝策略。线程池的拒绝策略有哪些？AbortPolicy ：直接抛出异常，默认使用此策略CallerRunsPolicy：用调用者所在的线程来执行任务DiscardOldestPolicy：丢弃阻塞队列里最老的任务，也就是队列里靠前的任务DiscardPolicy ：当前任务直接丢弃线程池怎么关闭知道吗？有shutdown() 方法和 shutdownNow()shutdown()方法是将线程池调整为关闭状态，要等所有线程执行完毕后再关闭shutdownNow()方法能立即停止线程池，正在跑的和正在等待的任务都停下了。线程池异常怎么处理知道吗？使用try-catch块捕获异常，并将异常信息记录到日志中在捕获到异常后，如果情况允许，可以将异常重新抛出，以便上层代码或其他处理机制能够更好地处理异常。确保线程池中的线程能够正确释放占用的资源，避免资源泄露。在异常处理时，需要考虑任务的状态，避免重复处理或者对已经完成的任务进行异常处理。设置监控机制，及时检测线程池异常情况，可以使用监控工具或者自定义报警机制，让开发人员及时介入。
你使用过的MQ技术有哪些RabbitMQ、RocketMQ、Kafka如何保证消息不丢失如果在生产者中丢失，可以使用事物机制，但是他是同步的很消耗性能，也可以开启确认机制，生产者在将消息发送到MQ后，等待MQ的确认响应。只有在收到MQ的确认后，生产者才认为消息已安全发送。如果没有收到确认，生产者可以重试发送消息。如果在MQ中丢失，可以开启持久化将消息存储到硬盘，可以保证持久性。如果在消费者中丢失，消费者在成功处理消息后发送ACK给MQ，表示消息已被处理。如果没有收到ACK，MQ可以将消息重新投递给其他消费者。RocketMQ如何保证消息的可用性 / 可靠性 / 不丢失呢？在生产者是通过请求确认机制，同步发送的时候没有发生议程就会响应OK，发生异常就会响应异常，异步发送的时候，要在回调方法中检查，如果发送失败应该去重试在存储是配置可靠优先的Broker参数来避免宕机消息丢失，消息会持久化到CommitLog日志中，即使宕机也会重新消费，他Broker的刷盘机制不管是同步或者异步都可以保证消息一定存储在内存中，它是生产者发送消息后等数据持久化到磁盘之后再返回响应给生产者。在消费者是消费时的确认机制，要等都执行完了后再发送消费确认。RocketMQ如何处理消息重复的问题呢？(如何保证消息幂等性)可以在业务消费逻辑上保证幂等性，就是多次调用和一次调用都是一样的也可以消息去重，就是保证每条消息都有一个唯一id，可以简历一个消费记录表，拿到消息后会去数据插入这个唯一id，如果出现重复消费就会出现主键冲突，那就不再处理这条消息就可以了。如何处理消息积压可以扩充消费者，来提高消费能力也可以把消息迁移到新的Topic，临时的Topic可以扩容消费者这样就可以处理消息积压RocketMQ中如何实现顺序消息他分为部分顺序和全局顺序全局顺序要把Topic 的读写队列数设置为 一，然后 Producer Consumer 的并发设置，也要是一，这样牺牲了高并发变成单线程他就可以实现顺序消息了。部分顺序的话要在Producer把同 ID 的消息发送到同一个 Message Queue里面，消费的时候要从同一个Message Queue里面顺序处理RocketMQ中如何实现消息过滤在 Broker 端按照 Consumer 的去重逻辑进行过滤，可以避免了无用的消息传输到 Consumer 端，缺点是加重了 Broker 的负担，实现起来相对复杂。在 Consumer 端过滤，比如按照消息设置的 tag 去重，缺点是有大量无用的消息到达了 Consumer 端只能丢弃不处理。RocketMQ中如何实现延迟消息在发送消息时，可以设置消息的延迟级别。RocketMQ 提供了几种预定义的延迟级别，分别表示不同的延迟时间。实际上他就是一个临时存储+定时轮询的方式实现了延迟消息，当Topic收到延迟消息后他不会直接把消息放到队列中去，会创建一个定时的队列，通过一个定时任务轮询这些队列，到期后，把消息投递到目标 Topic 的队列中，从而实现了延迟消息的效果RocketMQ中的死信死信队列就是用于处理无法被正常消费的消息的，当消息消费失败超过最大重试次数的时候就会把消息放入死信队列，我们应该监控死信队列去把无法消费的消息手动消费RocketMQ 中 Broker 是怎么保存数据的呢？主要的存储文件包括 CommitLog 文件、ConsumeQueue 文件、Indexfile 文件。CommitLog他默认大小1G，消息主要是顺序写入日志文件，当文件满了，写入下一个文件。ConsumeQueue是基于 Topic 的 CommitLog的索引文件IndexFile提供了一种可以通过 key 或时间区间来查询消息的方法。RocketMQ是怎么会消息文件进行读写的PageCache、顺序读写、零拷贝PageCache： 利用操作系统的PageCache来缓存文件内容，提高写入和读取的效率，避免频繁的磁盘IO操作。顺序读写： 消息的写入和读取都是基于顺序的方式进行，减少了磁盘寻道操作，提高了读写效率。零拷贝技术： 在数据传输过程中避免数据从一个缓冲区拷贝到另一个缓冲区，减少了数据拷贝的开销，提高了数据传输效率。
JVM内存结构程序计数器Java虚拟机栈本地方法栈Java堆方法区运行时常量池直接内存对象创建的过程JVM如何保证线程安全的JVM通过分配内存空间、初始化对象和调用构造函数等阶段保证对象创建的线程安全性。尽管创建过程中存在线程不安全的阶段，JVM通过独占性保证每个线程在初始化和构造对象时不受干扰。然而，在构造函数中可能存在耗时操作，需注意其他线程可能在对象未完全构造前访问，导致问题。因此，在编写构造函数时，要考虑多线程并发访问情况，确保构造函数的线程安全性。什么是内存溢出和内存泄漏常见的内存溢出和内存泄漏操作大对象长期不被清理，长生命周期对象持有生命周期对象，递归调用层次太深或者方法调用过多，IO流没有关闭CGRoots,是什么垃圾收集器通过判断哪些对象是可以被访问到的来确定哪些对象是存活的，而这些能够被访问到的对象通常包括以下几种类型虚拟机栈中的本地变量和引用方法区中的类静态属性引用的对象方法区中常量引用的对象本地方法栈中JNI（Java Native Interface）引用的对象如何判断对象仍然存活通过引用计数法与可达性分析方式来判断对象是否存活finalize方法功能是什么堆内存结构常见的垃圾回收算法标记-清除算法，它是一个基础回收算法，它分为两个阶段：标记阶段，从根对象出发，标记所有可达的对象；清除阶段，遍历堆中的所有对象，清除未标记的对象，回收空间，它缺点是堆空间会产生碎片，影响堆空间连续分配复制算法，将堆分为两个区域，每次只使用其中一个区域。当一个区域用尽时，将活动对象复制到另一个区域，然后清除已经不再使用的对象。复制算法避免了内存碎片，但要求堆空间至少为对象的两倍。标记-压缩算法，它先标记所有可达的对象，将所有未标记的对象压缩到堆的一端然后清除，并更新对象引用，它解决了碎片问题，但是压缩也会占用性能分代回收算法，它是根据对象的存活周期不同分为新生代和老年代，新生代使用复制清除算法，老年代使用标记算法，压缩算法三色标记算法，是一种增量算法，使用三种颜色来标记对象状态，避免长时间停顿并发标记-清除算法，使用并发线程进行垃圾回收，减少垃圾回收的停顿时间，提高系统的响应性。什么时候触发youngGC当Eden没有足够空间的时候会触发youngGC什么时候触发FulIGC对象youngGC触发前检查Old区是否充足，youngGC执行后将对象移动到Old区发现没有足够空间，在Old区空间不足的时候什么时候进入老年代在YoungGC每次迭代都会增加年龄。当年龄达到15的时候就会移动对象到老年代，当占用大量连续内存空间的对象回直接在老年代创建常见的垃圾回收器有哪些垃圾回收器和垃圾回收算法的关联什么是STW什么是OOPMAPCMS的垃圾回收过程G1的垃圾回收过程线上服务CPU过高如何排查linux的话使用top命令查看是哪个进程导致的，如果是java进程通过PID查询他进程ID 在通过线程ID，再通过线程ID打印具体哪个方法导致的，再去代码中找导致CPU飙升的地方
数据库设计的三大范式每一列字段都是原子的，比如产品编码列中，每个单元只能有一个编码；在满足第一范式的基础上，确保非主键属性完全依赖于主键；在满足第一二范式，确保非主键属性之间没有传递依赖。drop delete truncate区别dorp是用于表的删除，这个删除是无法进行恢复的；delete是用于表中数据的一行，可以使用ROLLBACK进行回滚的；truncate是清空表，会删除表中所有数据并且保留薄的结构，也是无法使用ROLLBACK进行撤销操作。count(1) count() count(列名)区别count(1)和count()都是统计所有行数，而count(1)会忽略具体列中的具体数据查询效率较高，count(列名)是查询该列中非NULL的所有列。SQL查询语句的执行顺序FROM 子句 ：从指定的表中获取数据。WHERE 子句 ：根据指定的条件筛选数据。GROUP BY 子句 ：根据指定的列对数据进行分组。HAVING 子句 ：对分组后的数据进行筛选，类似于 WHERE，但作用于分组数据。SELECT 子句 ：选择要查询的列，进行计算或数据处理。ORDER BY 子句 ：对结果进行排序。LIMIT/OFFSET 子句 ：根据指定的数量和偏移量返回结果的子集。InnoDB和MyISAM区别InnoDB 支持事务而MyISAM不支持事物InnoDB是行级锁而MyISAM是表级锁InnoDB支持崩溃恢复而MyISAM没有崩溃恢复机制InnoDB从 MySQL 5.6.4 开始支持全文索引，而MyISAM很早就支持不过它性能和功能方面相对较弱InnoDB会将数据和索引存储在内存缓存中，适合于对内存要求较高的应用，而MyISAM 也支持内存缓存，但与 InnoDB 相比，性能相对较低索引分类主键索引（Primary Key Index） ：主键索引是一种唯一性索引，用于标识表中的唯一记录。在主键索引下，数据行的值是唯一的，因此可以快速定位到特定的数据行。唯一索引（Unique Index） ：唯一索引保证索引列的值在整个表中都是唯一的，但可以有 NULL 值。通过唯一索引可以确保数据的完整性，同时提高检索效率。普通索引（Normal Index 或 Non-Unique Index） ：普通索引用于加速对表中数据的搜索和检索，但允许索引列有重复值。适用于频繁用于查询、排序和过滤的列。全文索引（Full-Text Index） ：全文索引用于对文本数据进行全文搜索，允许对文本内容进行关键词匹配。适用于需要进行文本搜索的场景，如文章内容、评论等。空间索引（Spatial Index） ：空间索引用于处理地理空间数据，如地理坐标点、地理区域等。可以用于查询地理位置相关的信息，如距离计算、区域判断等。组合索引（Composite Index 或 Compound Index） ：组合索引是由多个列组合而成的索引，用于加速多个列的联合查询。可以优化查询条件中涉及多个列的情况。索引在什么情况下会失效在使用模糊查询、使用or链接的条件、数据量过少、连接查询的时候选择了不正确的链接索引，这些都会导致索引失效。索引不适合哪些场景不适用于数据量小、增删改频繁的、大字段的列、维度表、频繁的批量操作索引存储的数据结构一般使用B+数的结构 也有B树结构为什么使用B+而不是普通二又树因为他更适合硬盘存储，减少了磁盘 I/O 次数，有序性强，平衡性好，能够减少高层索引的维护成本，查询效率稳定。聚簇索引和非聚簇索引区别区别主要在于数据存储方式、唯一性、查询性能和更新性能。聚簇索引下数据行的物理存储顺序与索引顺序相同，用于范围查询，要求键值唯一。非聚簇索引维护了键和数据行的映射，适用于插入和更新频繁的情况。选择索引类型要根据具体需求和数据库表的特性。回表和覆盖索引回表是指查询过程中需要通过索引再次查找表中的数据行，而覆盖索引是指索引已经覆盖了查询所需的字段，无需回表操作，从而提高了查询性能。优化查询性能时，选择合适的索引和避免回表操作是重要的考虑因素。什么是最左匹配原则最左匹配原则是数据库索引优化中的一个概念，在复合索引中，从索引的左边开始匹配查询条件，以便实现最佳的索引利用。如果一个复合索引包含多个列，那么在查询时，数据库会从复合索引的最左边开始，依次匹配查询条件中的列。只有当查询条件中的列依次从左到右与索引中的列匹配，才能有效地利用这个索引。一旦遇到一个不匹配的列，索引就不能继续使用。MySQL中的锁有哪几种共享锁（Shared Lock，也称读锁）：共享锁允许多个事务同时获取同一资源的锁，用于保证读操作的并发性，多个事务可以共享同一个资源的共享锁，不会互相阻塞。排他锁（Exclusive Lock，也称写锁）：排他锁只允许一个事务获取资源的锁，其他事务无法获取该资源的共享锁或排他锁。用于保证写操作的原子性。意向共享锁（Intention Shared Lock）：意向共享锁是一种在行级锁和表级锁之间的辅助锁，用于指示一个事务要在某个资源上获取共享锁。意向排他锁（Intention Exclusive Lock）：意向排他锁是一种在表级锁上的辅助锁，用于指示一个事务要在某个资源上获取排他锁。自增锁（Auto-Increment Lock）：用于保证自增操作的并发安全，MySQL在执行自增操作时会为相关的行加上自增锁，防止多个事务同时对同一行进行自增。间隙锁（Gap Lock）：用于防止幻读现象，间隙锁会锁定一个范围，阻止其他事务在这个范围内插入新的数据。临键锁（Next-Key Lock）：临键锁是 MySQL 中用于解决幻读问题的锁，它是间隙锁和记录锁的组合，用于保证范围查询的一致性。MySQL中事务的四大特性原子性、隔离性、一致性、持久性原子性（Atomicity）：原子性指事务是一个不可分割的最小工作单元，要么全部执行成功，要么全部不执行。如果事务中的任何一部分失败，整个事务会回滚到起始状态，保持数据的一致性。一致性（Consistency）：一致性指事务在执行前后，数据库的状态必须保持一致。这意味着事务应该将数据库从一个合法状态转移到另一个合法状态，不会破坏数据完整性和业务逻辑。隔离性（Isolation）：隔离性指多个事务并发执行时，每个事务都应该与其他事务隔离开来，互不干扰。每个事务的操作都应该在完全隔离的环境下进行，以防止并发访问引发的问题。持久性（Durability）：持久性指事务一旦提交成功，对数据库的改变就是永久性的，即使发生系统故障也不会丢失。数据库应该将事务的更改写入持久存储介质，以确保数据的持久性。MVCC怎么实现的他实际上是多版本并发控制实现事务隔离性的机制，每个事务在开始时会被分配一个唯一的时间戳，用于标识事务的先后顺序，数据行不仅保存当前的值，还会保存多个历史版本的值。每个版本都有一个与之相关的时间戳，当一个事务执行写操作时，不会直接修改原始数据行。而是将修改后的数据创建为一个新版本，并与事务的时间戳关联，当事务执行读操作时，只能看到在它开始之前已经提交的版本。这确保了事务只能看到自己开始之前的数据库状态，从而实现了隔离性。当事务提交后，其时间戳会被记录为提交时间。其他事务在此之后执行的读操作会看到该事务所做的修改。MySQL主从复制原理水平分表有几种路由方式一种常见方式是使用数据库中间件，如Sharding-JDBC、Mycat等，它们拦截SQL语句并根据配置将查询路由到对应的数据节点。另一种方式是代码封装，通过代码控制写操作走主库，读操作走从库。还可以结合分库分表策略，将不同的数据分散到不同的数据库或表中，以实现数据水平分片大数据量下的表如何删除和添加字段创建一个新表，将需要保留的字段迁移到新表中，然后重命名表，达到删除/添加字段的效果。MySQL数据库CPU飙升如何处理排查高耗CPU SQL ：通过系统命令（如top）查看是否由mysqld进程引起的，排查高耗CPU SQL语句并进行优化。索引优化 ：优化查询语句，添加合适的索引以减少全表扫描和数据访问开销。慢查询日志 ：开启慢查询日志，记录执行时间超过阈值的SQL语句，以便分析和优化。资源分配 ：合理配置数据库服务器的CPU和内存资源，防止资源争抢导致性能下降。分析工具 ：使用数据库性能分析工具（如Explain）分析查询执行计划，找出潜在的性能瓶颈。
Java 是值传递，还是引用传递java语言是值传递，如果是基本数据类型他是值的拷贝，不会影响原来的变量，如果是引用数据类型他是地址的拷贝因为指向了一个对象所以可以修改对象中的变量的值，如果是String类型他虽然是地址拷贝，但是String是不可修改的所以不能改原变量的值。深拷贝和浅拷贝如果是基本数据类型无论深拷贝还是浅拷贝都是直接复制一份新的如果是对象，浅拷贝是复制了一份地址，深拷贝是在堆空间中又复制了一份对象== 和 equals 的区别== 如果是基本数据类型他是直接比对值，如果是引用数据类型他比对的是地址值equals 他是Object中的方法，他如果不重写equals和hashCode方法的话是和==效果一样的都是比对地址值，如果重写了就会根据重新的内容去比对对象中地址值。String 和 StringBuilder、StringBuffer 的区别？String在创建后是不可更改的StringBuffer和String差不多他是线程安全的StringBuilder也是做字符串拼接的但是他是线程不安全的String str1 = new String("abc") 和 String str2 = "abc" 和 区别？区别的话是创建对象数量不一样，String str1 = new String("abc") 首先会在堆空间中创建一个String 如果字符串常量池中没有"abc"的话就会创建2个对象，如果有就是1个对象，而String str2 = "abc"会直接查字符串常量池中是否已经存在，如果存在就不会创建对象，如果不存在就会创建1哥对象。说一下你对注解的理解注解可以理解为是一个标记，可以在编译或者运行的时候处理一些事情，比如lombok可以在编译期间生成get set 构造等方法。什么是反射？应用？原理？就是在运行期间动态地获取类信息、创建类实例、调用类方法，原理的话就是JVM 进行类加载的时候，会加载字节码文件，将类型相关的所有信息加载进方法区，反射就是去获取这些信息，然后进行各种操作，在Spring中的一些注解都是使用了反射。JDK1.8 都有哪些新特性接口可以有默认方法Lambda 表达式和函数式接口Stream流式操作日期时间 APIOptional 类Stream 流用过吗用过的，在集合的操作的时候我喜欢使用Stream进行操作他可以使用map方法把集合中每个值做一个映射去操作Filter方法可以过滤一下内容，collect方法可以把每一个映射重新聚合成List、Map等
Spring中的循环依赖多个Bean之间互相引用，形成了一个循环的依赖关系。这种情况下，当Spring容器初始化这些Bean时，可能会出现问题，因为每个Bean在初始化时需要先创建依赖的Bean，而依赖的Bean又需要依赖其他的Bean，从而导致循环依赖问题。Spring怎么解决循环依赖的Spring会提前暴露还未初始化完成的Bean对象，这样在创建Bean时，即使有循环依赖，也可以通过提前暴露的引用来解决。这种方式适用于单例Bean，Spring也会为存在循环依赖的Bean创建一个代理对象，先创建一个代理对象作为依赖的引用，等到Bean初始化完成后，再将代理对象替换为实际的Bean，也可以使用构造器的方式进行注入，这样Bean在初始化时就可以得到它所依赖的Bean。为什么要三级缓存?二级不行吗?不行，他三级缓存是为了生成代理对象，如果是没有代理对象的情况他使用二级缓存是没有问题的。@Autowired的实现原理当Spring容器初始化时，会自动查找所有的Bean定义，然后尝试根据类的类型、名称等信息进行自动装配。在自动装配的过程中，Spring会查找与字段或方法参数类型匹配的Bean，然后将匹配的Bean注入到标注了@Autowired的地方。Spring会通过Bean的构造函数、Setter方法或直接字段注入来完成依赖注入。怎么理解Spring中的AOP他是一种面向切面编程的思想，能够实现横切关注点的模块化，提高代码的复用性和可维护性，同时把横切关注点集中管理，使代码更清晰和可维护。你平时怎么使用AOP的在一些日志的打印和性能监控方面说说JDK动态代理和CGLIB动态代理JDK动态代理适用于接口，CGLIB动态代理适用于无接口类，通过生成子类实现代理。选用取决于是否有接口，JDK更通用，CGLIB适合无接口情况。Spring事务隔离级别Spring框架支持以下五种事务隔离级别：DEFAULT（默认） ：使用底层数据库默认的事务隔离级别。READ_UNCOMMITTED（读未提交） ：允许一个事务读取另一个事务未提交的数据。可能导致脏读、幻读、不可重复读问题。READ_COMMITTED（读已提交） ：保证一个事务只能读取到另一个事务已提交的数据，可以避免脏读问题。REPEATABLE_READ（可重复读） ：保证一个事务在整个过程中可以多次读取同一数据，不会受其他事务的影响。可以避免脏读、不可重复读问题。SERIALIZABLE（串行化） ：最高的隔离级别，确保所有事务按照顺序依次执行，避免所有并发问题。Spring事务传播行为Spring框架中定义了七种事务传播行为，用于控制方法在不同事务上下文中的行为。以下是这些事务传播行为：REQUIRED（默认） ：如果当前存在事务，则加入该事务；如果没有事务，则创建一个新事务。是最常用的传播行为。SUPPORTS ：如果当前存在事务，则加入该事务；如果没有事务，则以非事务方式执行。MANDATORY ：要求当前必须存在事务，否则会抛出异常。REQUIRES_NEW ：无论当前是否存在事务，都会创建一个新事务，并在方法执行完毕后提交。NOT_SUPPORTED ：无论当前是否存在事务，都会以非事务方式执行。NEVER ：要求当前不存在事务，如果存在则抛出异常。NESTED ：如果当前存在事务，则在嵌套事务中执行；如果没有事务，则执行REQUIRED类似的操作。声明式事务在哪些情况下会失效当在同一个类的方法中调用另一个方法，而调用的方法带有声明式事务注解，事务可能会失效；捕获了异常而不重新抛出，声明式事务可能无法正确处理异常，导致事务无法回滚；非公开方法（private、protected等）上的声明式事务无法被代理，因为代理通常基于接口或类的public方法，在声明式事务中，如果使用编程式事务（如TransactionTemplate）来管理事务，可能会导致事务失效；如果运行时异常被捕获并不再次抛出，事务可能无法正确回滚；在多线程环境中，声明式事务可能无法正确传播，因为线程之间的事务隔离可能导致事务不生效。Spring MVC的工作流程客户端HTTP请求到Spring MVC应用的前端控制器DispatcherServletDispatcherServlet是Spring MVC的核心控制器，它接收到所有的客户端请求，并将请求分发给不同的控制器。：DispatcherServlet会查询Handler Mapping，它会根据请求的URL找到匹配的控制器（Handler）。找到匹配的控制器后，DispatcherServlet会将请求交给对应的Controller进行处理。Controller处理请求后，会返回一个ModelAndView对象，其中包含了模型数据和视图名。View Resolver找到视图模板后，会将模型数据注入视图模板中，生成最终的HTML响应。生成的HTML响应会由DispatcherServlet返回给客户端，完成请求-处理-响应的循环。Spring boot自动配置原理Spring Boot的自动配置是通过条件注解、自动配置类、spring.factories文件和配置属性等机制来实现的。条件注解判断何时应用自动配置，自动配置类提供预定义的Bean配置，spring.factories文件列出自动配置类，配置属性影响自动配置行为。如何自定义一个起步依赖自定义Spring Boot起步依赖的步骤如下：创建项目 ：使用Maven或Gradle创建一个新项目，作为你的自定义起步依赖项目。定义自动配置类 ：在项目中创建一个自动配置类（带有@Configuration注解），在其中定义需要自动配置的Bean和逻辑。创建条件注解 ：编写一个自定义的条件注解（带有@Conditional注解），用于决定何时应用你的自动配置。这个条件注解可以根据特定的条件来判断是否应用你的配置。创建spring.factories文件 ：在src/main/resources/META-INF目录下创建一个spring.factories文件，其中列出自动配置类和条件注解的全限定名。这个文件会被Spring Boot自动扫描，用于加载自定义的自动配置。编写README文档 ：创建一个清晰的README文档，描述你的起步依赖的用途、功能和使用方法，帮助其他开发者理解如何使用它。发布到仓库 ：将你的自定义起步依赖打包，并将其发布到Maven或其他仓库中，以便其他项目可以通过依赖管理工具引入它。Spring Cloud中的核心组件及其应用Eureka ：Eureka是一个服务注册和发现的组件Ribbon ：Ribbon是一个负载均衡的客户端Feign ：Feign是一个声明式的HTTP客户端Hystrix ：Hystrix是一个断路器和容错的库Zuul ：Zuul是一个网关服务Config ：Config用于集中管理微服务的配置信息Bus ：Bus用于在微服务之间传播状态变化和事件Stream ：Stream是一个事件驱动的微服务通信框架Sleuth ：Sleuth用于分布式系统中的请求追踪和跟踪nacosSpring 中应用了哪些设计模式呢?工厂模式 : Spring 容器本质是一个大工厂，使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。代理模式 : Spring AOP 功能功能就是通过代理模式来实现的，分为动态代理和静态代理。单例模式 : Spring 中的 Bean 默认都是单例的，这样有利于容器对 Bean 的管理。模板模式 : Spring 中 JdbcTemplate、RestTemplate 等以 Template 结尾的对数据库、网络等等进行操作的模板类，就使用到了模板模式。观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。ApplicationRunner适配器模式 :Spring AOP 的增强或通知 (Advice) 使用到了适配器模式、Spring MVC 中也是用到了适配器模式适配 Controller。策略模式：Spring 中有一个 Resource 接口，它的不同实现类，会根据不同的策略去访问资源。说一说什么是 IOC? 什么是 DI?IOC就是控制反转，将对象的创建、生命周期和对象的关系交给容器来管理，我们想要什么对象容器就给我们什么对象，DI的话就是当容器实例化一个对象的时候会把他的依赖对象注入给他能说一下 Spring Bean 生命周期吗?他分为四个阶段实例化（Instantiation）、属性赋值（Populate）、初始化（Initialization）、销毁（Destruction）解析类得到BeanDefinition如果有多个构造方法，则要推断构造方法确定好构造方法后，进行实例化得到一个对象对对象中的加了@Autowired注解的属性进行属性填充回调Aware方法，比如BeanNameAware,BeanFactoryAware调用BeanPostProcessor的初始化前的方法调用初始化方法调用BeanPostProcessor的初始化后的方法，在这里会进行AOP如果当前创建的bean是单例的则会把bean放入单例池使用beanSpring容器关闭时调用DisposableBean中destory(0方法Spring 中的单例 Bean 会存在线程安全问题吗？会存在，因为是单例的，所有线程都会使用这一个Bean，如果这个Bean是个无状态的，就是线程的操作对Bean中成员变量不会执行查询以外的操作他就是线程安全的。
@Configuration public class GlobalCorsConfig { /** * 允许跨域调用的过滤器 */ @Bean public CorsFilter corsFilter() { // 创建一个跨域的配置类 CorsConfiguration config = new CorsConfiguration(); // 允许白名单域名进行跨域调用 // 这个是配置允许哪些域名进行跨域调用 *代表所有域名 // 这个配置可以写多个 config.addAllowedOrigin("*"); // 允许跨越发送 cookie config.setAllowCredentials(true); // 放行全部原始头信息 config.addAllowedHeader("*"); // 允许所有请求方法跨域调用 // 这个配置也可以写多个 POST PUT GET DELETE OPTIONS config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // 访问这个项目的所有请求都会跨域调用 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
ArrayList和Vector有什么区别?Vector 他是线程安全的动态数组 Vector 扩容是扩大一倍，ArrayList是或扩充50%ArrayList 和 LinkedList 有什么区别？ArrayList底层是数组，他总体来说增删慢查询快，因为每次增删都需要调整数据在数组中的位置，除了在头尾，查询可以根据下标直接拿到LinkedList底层是双向链表，他总体来说查询慢增删快，因为增删只需要调整数据的前后指针即可，除了头尾，但是他查询的话需要遍历整个链表ArrayList 的扩容机制了解吗？他会先检查是否需要扩容，如果当前容量+1大于数组长度就会触发扩容，在扩容的时候会新建出一个原来数组长度的1.5倍然后把旧数据拷贝过去，再进行添加新的元素。有哪几种实现 ArrayList 线程安全的方法？使用CopyOnWriteArrayList使用Vector使用Collections.synchronizedList 包装 ArrayList使用 ArrayList 时，应用程序通过同步机制去控制 ArrayList 的读写。HashMap的数据结构在1.8以前是数组+链表的结构，1.8以后是会在链表数据超过一定阈值的时候转换为数组+红黑树的结构来提高查询效率。为什么使用红黑树而不是二叉树或平衡树因为二叉树或平衡树他们横向扩展差，数据过多的话会让树的高度变高导致查找、插入和删除操作的效率下降，而红黑树就会解决这个问题HashMap的put流程首先会对key做哈希运算取到哈希值，会根据这个哈希值找到他在数组中的位置，这个时候会出现两种情况，如果当前的位置是空的就会直接将值插入，如果这个位置不是空的就会比对他的key值是否相等，如果相等就会对已有的值进行替换，如果不想等就会说明发生了哈希冲突会在这个位置添加一个新的节点，如果链表长度超过8的时候且当前HashMap的容量达到了一个较大的阈值（负载因子超过0.75），会触发扩容操作，将HashMap的容量增加一倍，并重新计算每个元素在新数组中的索引位置。HashMap的get流程会先根据key做哈希运算取到哈希值，根据这个哈希值找到数组的对应位置，如果这个位置没值就会返回null，如果有值那么有可能是多个或者一个，一个的话就会直接取到值并进行返回，如果是多个值会遍历链表并判断是否是这个key并取到值，如果遍历会没有值就会返回null。HashMap扩容机制如果链表长度超过8的时候且当前HashMap的容量达到了一个较大的阈值（负载因子超过0.75），会触发扩容操作，将HashMap的容量增加一倍，并重新计算每个元素在新数组中的索引位置，扩容后，负载因子会相应地降低，这样可以提供更好的性能和更低的冲突概率。初始化HashMap传递初始容量17数组长度实际为多少HashMap在设置初始容量并不是直接设置数组长度，而是通过将传递的初始容量减去1后进行位运算，最终的数组长度就是经过位运算得到的值，所以初始容量是17数组长度实际为32。如何解决Hash冲突链表+红黑树，通过将链表转换为红黑树，可以减少链表查找的时间复杂度。这样，即使在有大量哈希冲突的情况下，HashMap仍然能够保持较高的性能。链表转红黑树的阈值为什么是8根据以实际测试与优化得出阈值为8时是一个平衡性能和内存消耗的考量，如果全部转为红黑树他每个节点都需要存颜色、父节点、左子节点、右子节点的指针会导致内存消耗增加。扩容因子为什么是0.75经过实践和优化，这个值既允许在数组中保持一定的空闲槽位，以减少冲突的概率，又可以有效利用内存空间，所以扩容因子选择为0.75是为了在HashMap的负载因子和内存利用率之间找到一个平衡点，以提供较好的性能和空间利用率。为什么 HashMap 的容量是 2 的倍数呢？我看过HashMap的底层源码他注释上写的容量是2的时候在时间与存储上都是最佳的。HashMap1.7和1.8的区别数据结构从数组+链表 改成了数组+链表+红黑树链表的插入方式从头插法改成尾插法，因为头插法在多线程环境扩容的时候可能会产生死循环1.7是先判断是否需要扩容再插入数据，1.8以后是先插入数据再判断是否需要扩容1.7散列函数做了4次位移和4次异或，1.8只做了1次HashMap和HashTable的区别?HashTable是线程安全的，HashMap是线程不安全的HashTable的key和balue都不可以出现null，而HashMap可以HashTable默认容量是11并且扩容不要求一定是2的整数次幂触发扩容时会变成原来的2倍加1，HashMap默认容量是16扩容必须是2的整数次幂触发扩容时会变成原来的2倍分段锁CAS+synchronized如何保证HashMap的线程安全HashMap内部节点是有序的吗LinkedHashmap:是怎么实现有序的TreeMap:是如何实现有序的HashMap和HashSet的区别
maven坐标 org.springframework.boot spring-boot-starter-websocket 配置类/** * WebSocket配置类，用于注册WebSocket的Bean */ @Configuration public class WebSocketConfiguration { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }WebSocket 服务/** * WebSocket服务 */ @Component @ServerEndpoint("/ws/{sid}") public class WebSocketServer { //存放会话对象 private static Map<String, Session> sessionMap = new HashMap(); /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("sid") String sid) { System.out.println("客户端：" + sid + "建立连接"); sessionMap.put(sid, session); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, @PathParam("sid") String sid) { System.out.println("收到来自客户端：" + sid + "的信息:" + message); } /** * 连接关闭调用的方法 * * @param sid */ @OnClose public void onClose(@PathParam("sid") String sid) { System.out.println("连接断开:" + sid); sessionMap.remove(sid); } /** * 群发 * * @param message */ public void sendToAllClient(String message) { Collection<Session> sessions = sessionMap.values(); for (Session session : sessions) { try { //服务器向客户端发送消息 session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } }