9月8日扒面经
慢sql日志的排查和调优
- 开启慢查询日志:首先需要确保数据库的慢查询日志功能已经开启。在MySQL中,可以通过设置slow_query_log参数为1来开启慢查询日志,并设置long_query_time参数来定义慢查询的阈值。
- 定位慢查询语句:根据慢查询日志,找出执行时间超过阈值的SQL语句。可以使用工具如mysqldumpslow或直接分析慢查询日志文件来定位慢查询语句。
- 分析执行计划:对于定位到的慢查询语句,可以使用EXPLAIN命令来查看其执行计划。执行计划可以帮助我们理解查询的执行过程,找出可能存在的性能问题。
- 优化查询语句:根据执行计划和慢查询的特点,进行查询语句的优化。常见的优化手段包括添加索引、优化查询条件、减少数据访问量等。
- 重构数据模型:如果查询语句的优化无法满足性能需求,可能需要重新设计数据库的数据模型。这包括调整表结构、拆分表、合并表等。
- 配置数据库参数:除了优化查询语句和数据模型,还可以通过调整数据库的配置参数来提升性能。例如,调整缓冲区大小、并发连接数、线程池大小等。
- 使用缓存:对于一些频繁查询但不经常变化的数据,可以考虑使用缓存技术,减少数据库的访问压力。
- 监控和调优:持续监控数据库的性能指标,如查询响应时间、并发连接数、缓冲区命中率等。根据监控结果,进行进一步的调优和优化。
线程池是怎么工作的
1.创建线程池;2.提交任务;3.任务队列; 4.线程调度; 5.执行任务
- 创建线程池:应用程序创建一个线程池,指定线程池的大小和其他相关参数。线程池中的线程数量通常根据系统的处理能力和任务的性质来确定。
- 提交任务:应用程序将需要执行的任务提交给线程池。任务可以是实现了Runnable接口或Callable接口的对象。
- 任务队列:线程池维护一个任务队列,用于存储待执行的任务。当线程池中的线程空闲时,它们会从任务队列中获取任务并执行。
- 线程调度:线程池会根据任务队列中的任务数量和线程池的配置来动态调整线程的数量。如果任务队列中的任务过多,线程池会创建新的线程来处理任务;如果任务队列中的任务较少,线程池会销毁多余的线程,以节省资源。
- 执行任务:线程池中的线程会从任务队列中获取任务,并执行任务的逻辑。执行完任务后,线程会返回线程池,并等待下一个任务。
线程池队列要设置有界还是无界?
数据传输,比如RPC or HTTP,使用数据类型,用基本类型还是包装类型好?
线程池并发时,线程安全怎么解决?
1.使用线程安全的数据结构:如ConcurrentHashMap、CopyOnWriteArrayList等,它们在内部实现了同步机制,可以保证多个线程并发访问时的安全性。
2.使用锁机制:可以使用synchronized关键字或者Lock接口 来实现互斥访问共享资源。
3.使用线程安全的设计模式:如单例模式、享元模式等,来保证共享资源的安全访问。
如果你要去对一个map去维护线程安全,除了用synchronized,有其他更好的方式吗?
使用ConcurrentHashmap:它通过分段锁(Segment)方式来实现并发访问的安全性,不同的线程可以访问不同的分段,从而提高并发性能。
使用Collections.synchronizedMap():可以使用Collections类提供的synchronizedMap()方法来将普通的Map转换为线程安全的Map。该方法会返回一个包装后的线程安全的Map对象,内部通过使用synchronized关键字来实现线程安全。
并发工具类来实现线程安全的map,封装一个工具类
使用读写锁:可以使用读写锁(ReadWriteLock)来实现对Map的并发访问。读写锁允许多个线程同时读取Map,但只允许一个线程写入Map。通过使用读写锁,可以提高并发性能。
ConcurrentHashMap如何保证线程安全?
- 分段锁(Segment):ConcurrentHashMap内部将数据分成多个段(Segment),每个段都是一个独立的HashMap,拥有自己的锁。不同的线程可以同时访问不同的段,从而提高并发性能。默认情况下,ConcurrentHashMap的段数为16,可以通过构造函数参数来指定。
- 读写分离:ConcurrentHashMap允许多个线程同时读取Map,而不需要加锁。这是因为读操作不会对Map进行修改,因此不会引发线程安全问题。只有在写操作时,才需要获取相应段的锁,保证写操作的原子性和线程安全性。
- volatile关键字:ConcurrentHashMap内部使用了volatile关键字来保证内存可见性。在读操作时,可以确保读取到最新的数据。
JVM的内存结构.
1.程序计数器
程序计数器(Program Counter Register)也被称为 PC 寄存器,是一块较小的内存空间。它可以看作是当前线程所执行的字节码的行号指示器。
2.Java虚拟机栈
Java 虚拟机栈描述的是 Java 方法执行的线程内存模型:方法执行时,JVM 会同步创建一个栈帧,用来存储局部变量表、操作数栈、动态连接等。
3.本地方法栈
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。
4.Java堆
此内存区域的唯一目的就是存放对象实例,Java 里“几乎”所有的对象实例都在这里分配内存。
5.方法区
方法区是比较特别的一块区域,和堆类似,它也是各个线程共享的内存区域,用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
哪些是线程共享,线程私有?
共享:堆 方法区
私有:程序计数器,两个栈
CAS存在什么问题?
如果有人攻击,或者是爬虫,出现这种情况,导致异常流量,服务端角度怎么去解决?
Bean注入的方式
构造器注入 setter注入 注解注入
A接口有两个实现,产生的两个bean,怎么去区分?
使用@Qualifier注解来区分不同实现类
集群中数据如何分区
节点取余分区
使用特定数据,对响应的hash值取余,来确定映射到那个节点
一致性哈希分区
hash空间为一个圆环,将缓存节点ip进行hash取余,放置到圆环上,对key进行hash取余,确定在圆环位置,然后顺时针行走,遇到第一个节点就存入
虚拟槽分区
一致性哈希的基础上,引入了虚拟节点,Redis使用的就是这个方案,虚拟节点称为槽, 槽介于数据和实际节点之间,每个实际节点中包含一定数量的槽,每个槽存储一定范围内的哈希
获取线程的返回值怎么做?
必须实现callable接口才有返回值,Future来接收返回值
创建callable对象
创建executorService调用submit方法提交任务。
获取线程的返回值怎么做?
MySQL的sql语句一般会怎么优化
使用合适索引
避免全表扫描
限制返回的数据量
避免重复查询
子查询和连接
18、ReentrantLock怎么实现公平锁的
ReentrantLock Java提供的一种可重入的互斥锁,它可以用来保证线程之间的互斥访问。ReentrantLock提供了两种锁的获取方式:公平锁和非公平锁。
要实现公平锁,可以在创建ReentrantLock对象时传入true参数,表示使用公平锁。默认情况下,ReentrantLock使用非公平锁。
ReentrantLock fairLock = new ReentrantLock(true);
使用公平锁时,ReentrantLock
会按照线程的请求顺序来获取锁。当有多个线程等待获取锁时,公平锁会按照先来先得的原则,保证等待时间最长的线程最先获取到锁。这样可以避免线程饥饿现象,保证所有线程都有公平的机会获取到锁。
需要注意的是,使用公平锁可能会降低系统的吞吐量,因为每次获取锁时都需要进行竞争和调度。而非公平锁则允许当前持有锁的线程再次获取锁,这样可以提高系统的吞吐量。
19、JDK1.8的HashMap的hash函数做了什么优化20、为什么HashMap有个负载因子的设计
21、HashMap解决了多线程操作导致死循环问题吗22、HashMap需要插入1000条数据,你怎么设置HashMap让性能比较高
23、Redis为什么会产生big key问题
24、Redis渐进式hash有了解吗
25、Redis做分布式锁有什么要注意的
26、MySQL的sal语句一般会怎么优化
27、explain会关注哪些字段
28、联合索引为啥会有最左前缀的原则
29、SpringBoot的run方法具体执行哪些步骤
dis渐进式hash有了解吗