-
锁
数据库中事务的隔离性就是通过锁和mvcc(多版本并发控制)来实现的。锁分为悲观锁和乐观锁两种,悲观锁是指在数据并发访问中会发生冲突,因此在操作数据的时候会进行加锁,防止其他事务对其修改,通过SELECT ... FOR UPDATE 或者 LOCK IN SHARE MODE 语句来实现悲观锁。乐观锁是指在数据访问时不认为会发生冲突,操作数据的时候不加锁,而是在事务提交的时候进行验证,如果监测到冲突,则回滚事务。MySQL 中的乐观锁通常通过添加版本号或时间戳来实现。
MVCC(多版本并发控制 )是一种数据库并发控制机制,指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图。
隐藏字段是指在MySQL中给每一个表都设置了隐藏字段,其中有一个trx_id(事务id)记录每一次操作的事务id,是自增的,另一个是回滚指针,指向上一个版本的事务版本记录地址。
undo log主要作用就是记录回滚日志,存储老版本的数据,
readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据。不同的隔离级别快照读是不一样的,最终的访问的结果不一样。
MVCC 与锁机制不同之处在于,它通过版本控制来实现事务的隔离,而不是依赖锁来限制并发访问。MySQL 中的锁和 MVCC 都是为了处理并发访问而设计的机制,但它们的实现方式和解决的问题有所不同。
-
InnoDB存储引擎
是MySQL最常用的存储引擎之一,具有事务支持、外键约束、MVCC支持、崩坏恢复等特点功能 。其中Buffer Pool是其关键组件之一,用于缓存数据库表和索引数据页的内存区域。Buffer Pool 的主要作用是减少磁盘 I/O 操作。它将经常访问的数据页缓存在内存中,使得数据库系统能够更快地读取和写入数据,而不必每次都访问磁盘。内存分配:通过配置参数指定buffer pool的大小。
LRU:使用LRU算法来管理数据页的替换。(将最近最少使用的数据页或缓存块替换出去,以便为新的数据页或缓存块腾出空间。)
-
索引的数据结构
索引是一种保证数据库对数据进行高效搜索访问的数据结构,底层是B+树。B+树只在叶子节点上存储数据,非叶子节点只存储指针。并且底层是双向链表。它的阶数更多,路径更短。而B树非叶子节点和叶子节点都存放数据。
-
索引失效
索引没有遵循最左匹配法则
模糊查询如果%号在前面也会导致索引失效
在添加索引的字段上进行了运算操作或者类型转换也会导致索引失效。
-
volatile
volatite是java中的一个关键字,用来实现线程的可见性和有序性。可见性是指一个线程修改了共享变量后,其他线程能够立刻看到这个修改的值。每次使用被volatile修饰的变量都会到内存中去读取。但它并不能保证原子性(需要用锁)。它通过插入特定的内存屏障禁止JVM执行重新排序,从而实现有序性。
-
垃圾回收器 (GC)
负责运行的时候自动管理内存分配和释放,以便回收不再使用的对象 。防止内存泄漏,提高程序性能serial GC:单线程垃圾回收器
Parallel GC:多线程进行垃圾回收
CMS:并发的垃圾回收器,垃圾回收大部分阶段和程序线程并发执行
G1 GC:面向大内存堆的垃圾回收器,通过划分堆内存为多个小区域并多阶段回收
ZGC:JDK11引入的低延迟的垃圾回收器,主要针对大内存堆并要求GC停顿时间极短的应用场景。
Shenandoah GC:JDK12引入的低停顿时间的垃圾回收器,与ZGC类似。
-
延迟队列的底层实现?
基于优先队列和时间堆的特性。结合定时任务或者定时器来实现对延迟元素的定期检查和处理。基于优先队列-元素封装-延迟时间排序-定期检查-定时触发-线程安全性。
-
redis分布式锁
redis中通过setnx设置,因为redis是单线程的,所以只能有一个客户端对某一个key设置值,在没过期或者删除key的时候其他客户端是不能设置这个key的。
通过redis分布式锁进行秒杀,保证秒杀的顺序性可以采用分布式锁,通过限流措施控制请求并发量,然后通过使用消息队列(kafka)将秒杀请求排队处理。 -
redis秒杀,用MQ同步mysql数据,怎么保证mysql不超卖
在秒杀商品库存减少的操作前加入分布式锁,确保同一时刻只有一个线程能够执行库存减少操作。MQ 消费者幂等性处理,确保同一条消息只被处理一次。MQ 消费者顺序处理,确保消息的消费顺序与消息的产生顺序一致。消息确认机制,使用消息确认机制(如 ACK 机制)向 MQ 确认消息已经被处理,确保消息不会被重复消费。
-
策略模式
策略模式(Strategy Pattern)是一种行为设计模式,它允许在运行时选择算法的行为,即在不同的情况下能够动态地切换算法。策略模式将不同的算法封装在独立的类中,并使它们可以互相替换,从而使得算法的选择可以独立于使用算法的客户端。 -
手写单例(线程安全)双重校验锁
java
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
-
怎么让volatile有原子性
volatile保证了变量的可见性以及程序执行的有序性,但不能保证原子性,可以用synchronized关键字或者原子类。synchronized保证了原子性,但每次只能有一个线程访问方法,效率低。用原子类AtomicInteger 类来替代普通的 int 类型,底层通常依赖原子级别的操作指令,比如CAS(比较交换)。CAS是乐观锁机制,它在执行时会比较某个内存位置的值与预期值,如果相等,则将该位置的值更新为新值;如果不相等,则不做任何操作。如果 CAS 操作失败(即内存位置的值与预期值不相等),则需要进行重试。通常会使用循环来反复尝试 CAS 操作,直到操作成功为止。但存在ABA问题。(可以设置版本号或者时间戳来解决)。
-
接口和抽象类
接口的成员变量只包括常量,public static final ,方法都是抽象方法,可以多继承,用来定义规范
抽象类中可以包含普通成员变量、方法以及抽象方法。普通方法有实现,抽象方法只有声明,只能单继承。
二者都不能实例化。都用来定义规范,描述一类对象的行为。二者都支持扩展,可以在子类中添加新的方法和属性。
-
final,finally,finalize
final 用于修饰类、方法和变量,表示不可变的;finally 用于异常处理,表示无论是否发生异常都会执行的代码块;finalize 是一个方法,在对象被垃圾回收器回收时调用,用于对象的资源释放和清理。
-
threadlocal原理,父线程怎么同步子线程?
ThreadLocal 是 Java 中的一个线程封闭技术,它允许将变量与线程关联起来 ,使得每个线程都拥有自己的变量副本 。这样可以在多线程环境下确保变量的线程安全性
ThreadLocal 使用一个特殊的内部类 ThreadLocalMap ,它是 ThreadLocal 的静态内部类,用于存储线程局部变量。键为 ThreadLocal 实例,值为线程局部变量。要获取线程局部变量,只需通过 ThreadLocal 的 get() 方法获取即可。要设置线程局部变量,只需通过 ThreadLocal 的 set() 方法设置即可。ThreadLocalMap 使用弱引用 来保存 ThreadLocal 实例,当 ThreadLocal 实例被回收时,对应的键值对也会被清理。
父线程同步子线程
在多线程环境下,父线程需要同步子线程的执行,可以通过 join() 方法来实现。join() 方法的作用是等待调用该方法的线程执行完毕后再继续执行。(保证线程的执行顺序)谁调用join,谁先执行
-
synchronized和Lock区别?
synchronized 是一种隐式锁,使用方便但灵活性较差;而 Lock 是一种显式锁,灵活性更高,但使用起来较为复杂,需要手动管理锁的获取和释放。
synchronized是java中的关键字,内置锁,可以对代码块、实例对象、类对象加锁。可重入(获取锁的线程可以多次获取同一个锁而不产生死锁)。可以自动释放锁,不可以中断,没有获取锁的其他线程只能等着。
Lock:Java中的一个接口,需要手动调用获取并释放锁,可以中断,支持公平锁和非公平锁。高并发下性能更好,但容易出错。
-
synchronized锁升级
synchronized 关键字在底层实现时会根据竞争的情况进行锁的升级,主要有偏向锁、轻量级锁和重量级锁三种状态。当一个线程获得了对象的锁,并且没有其他线程竞争时,JVM 会使用偏向锁来提升性能。当有多个线程竞争同一个锁时,JVM 会将偏向锁升级为轻量级锁(CAS)。如果轻量级锁获取锁失败,表示有多个线程同时竞争锁,则轻量级锁会升级为重量级锁。重量级锁会导致其他线程进入阻塞状态,性能较差。锁只能升级,不能降级。
-
说几种Lock,读写锁底层原理
reentrantlock,ReentrantLock 实现了 Lock 接口,是一个可重入且独占式的锁,和 synchronized 关键字类似。不过,ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁(默认非公平锁)等高级功能。
ReentrantReadWriteLock(基于AQS)读写锁(可重入)ReentrantReadWriteLock 其实是两把锁,(ReentrantReadWriteLock 内部维护了两个 ReentrantLock 实例,一个用于读操作(ReadLock),一个用于写操作(WriteLock)。)一把是 WriteLock (写锁),一把是 ReadLock(读锁) 。读锁是共享锁,写锁是独占锁。读锁可以被同时读,可以同时被多个线程持有,而写锁最多只能同时被一个线程持有。
-
ABA问题(CAS中)
CAS中(VEN),V是读取的值,E是期望值,N是新的值。当且仅当V=E的时候,才会将N写入,但是在读取之后,可能有其他线程读取了数据并修改了数据,之后又将数据改回了V,这时候就不能确定数据是否修改过了。
CAS 经常会用到自旋操作来进行重试,也就是不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销。
ABA 问题的解决思路是在变量前面追加上版本号或者时间戳。
-
AQS原理
AQS(AbstractQueuedSynchronizer)是 Java 并发包中的一个抽象基类,用于构建各种同步器(如锁、信号量、计数器等)。它提供了一种基于 FIFO 等待队列的同步机制,是实现并发控制的基础框架。悲观锁,手动开关锁。
在AQS中维护了一个使用了volatile修饰的state 属性来表示资源的状态,0表示
无锁,1表示有锁
提供了基于 FIFO 的等待队列 ,(**先进先出队列,新元素插入到队尾,而最老的元素位于队头)**类似于 Monitor 的 EntryList(关联bolcked状态的线程)
条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的
WaitSet(关联wait状态线程,调用了wait方法)
-
mysql聚簇索引和非聚簇索引
聚簇索引主要是指数据与索引放到一块,B+树的叶子节点保存了整行数据 ,有且只有一个,一般情况下主键在作为聚簇索引的。
非聚簇索引值的是数据与索引分开存储,B+树的叶子节点保存对应的主键,可以有多个,一般我们自己定义的索引都是非聚簇索引
-
回表查询
回表的意思就是通过二级索引(非聚簇索引)找到对应的主键值,然后再通过主键值找到聚集索引中所对应的整行数据,这个过程就是回表
覆盖索引:
覆盖索引是指select查询语句使用了索引,在返回的列,必须在索引中全部能够找到 ,如果我们使用id查询,它会直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。如果按照二级索引查询数据的时候,返回的列中没有创建索引,有可能会触发回表查询,
-
mysql 如何保证事务(三大日志)
它是由一个或多个数据库操作组成的逻辑工作单元 ,这些操作要么全部执行成功,要么全部失败,从而保证数据库的一致性和完整性。(ACID)原子性、一致性、隔离性、持久性MySQL 通过三大日志(Redo Log、Undo Log、Binlog)来保证事务的持久性、一致性和隔离性
redo log(重做日志):用于保证事务的持久性当事务提交时,Redo Log 记录了事务对数据库的修改操作,包括修改了哪些数据、如何修改以及修改前后的数据值等 。
在数据库崩溃或者异常情况下,MySQL 可以通过 Redo Log 来重新执行已提交但尚未持久化到磁盘的事务,从而保证事务的持久性。undo log(回滚日志):实现事务的回滚和MVCC(多版本并发控制)在事务执行过程中,Undo Log 记录了事务所做的修改操作的逆操作,即事务的回滚信息 。
在事务回滚或者数据库崩溃恢复的过程中,MySQL 可以使用 Undo Log 来撤销已提交的事务所做的修改,从而保证事务的一致性。
bin log(归档日志):二进制日志 ,记录了数据库的所有修改操作,包括数据的增删改操作和数据定义语句主要用于实现数据库的备份、恢复和主从复制等功能。
-
mysql间隙锁
MySQL 中的间隙锁(Gap Lock)是一种用于多版本并发控制(MVCC)的锁机制,用于防止并发事务在相同范围内插入数据时产生幻读问题。
间隙锁是在索引的键值范围上加锁的,而不是在具体的数据行上加锁 -
jvm分区
-在 Java 虚拟机(JVM)中,分区(Partition)是指将堆内存划分为不同的区域,以便更有效地管理内存和执行垃圾回收 。常见的分区包括新生代 (Young Generation)、老年代 (Old Generation)和持久代 (Permanent Generation,JDK 8 以前的版本)或元空间 (Metaspace,JDK 8 及以后的版本)等。
新生代:主要存放新创建的对象
老年代:主要用于存放长期存活的对象
持久代/原空间:用于存放 Java 类的相关信息,元空间是 JDK 8 引入的新的实现方 式,不再受到固定大小的限制,而是通过本地内存来存储类的元数据,从而提高了内存管理的灵活性和效率。
-
jvm垃圾回收机制都有哪些?
标记-清除算法:标记 出所有活动对象,然后清除未被标记 的对象来回收内存空间
复制算法:将堆内存分为两个区域,每次只使用其中一个区域。当一个区域被占满后,将存活的对象复制到另一个区域中,并将原区域的内存全部清空
标记-整理算法:在标记阶段标记出所有活动对象,并将它们向一端移动,然后清理出端边界以外的内存空间
分代算法:基于对象的生命周期分为不同的代,通常将堆内存分为新生代和老年代。新创建的对象会被分配到新生代,而经过多次垃圾回收仍然存活的对象会被晋升到老年代
增量式垃圾回收算法:将整个垃圾回收过程分解成多个小步骤,每次只执行一小部分垃圾回收操作。这样可以减少垃圾回收的停顿时间,提高系统的响应性能
并行垃圾回收算法:使用多个线程同时执行垃圾回收操作,以提高垃圾回收的效率
CMS算法:以低停顿时间为目标的垃圾回收算法,它在应用程序运行的同时进行垃圾回收。CMS 算法采用标记-清除算法
G1算法:基于分代的、并发的、并行的垃圾回收器,旨在实现低延迟和高吞吐量的垃圾回收。G1 算法使用分代思想,但是不再局限于新生代和老年代,而是将堆内存划分为多个大小相等的区域(Region),并采用不同的垃圾回收策略来处理不同的区域。
-
1.8hashmap底层结构,线程安全吗?哈希表扩容头插尾插?
结构:
数组+链表+红黑树(初始化数组长度为16,达到扩容阈值(数组长度*0.75)扩容为2倍。数组长度大于64,链表长度大于8,链表转换成红黑树)
不是线程安全的。HashMap 在多线程环境下仍然是非线程安全的,因为它的操作不是原子性的,且没有提供任何线程安全的保证 。如果需要在多线程环境下使用 HashMap,并且要求线程安全,应该使用 ConcurrentHashMap 或者 Collections.synchronizedMap 来保证线程安全性。其中concurrenthashmap底层和1.8hashmap一样,数组+链表+红黑树。采用CAS+synchronized保证并发安全。其中CAS控制数组节点的添加。synchronized只锁定当前链表或红黑树的首结点。只要hash不冲突,就不会发生并发问题。
头插法:扩容的时候,遍历原来的哈希桶,重新计算哈希值,并根据新数组大小重新分配到新的桶中。重新分配元素的时候把新元素插入在链表的头部 。简单迅速,不用遍历,但是会改变原来的元素顺序,
尾插法:扩容时遍历原来的哈希桶,将每个桶中的元素重新计算哈希值。并根据新数组的大小重新分配到新的桶中。重新分配的时候把新元素插入到链表的尾部。保障了元素的原来的顺序,但需要额外的遍历操作。
-
可重入锁的原理
支持同一个线程对同一把锁多次获取的锁机制。基于计数器和持有者线程,其中计数器:每个锁对象内部维护了一个计数器,用于记录当前线程对该锁的加锁次数,初始为0;持有者线程:锁内部还维护了一个持有者线程的引用,记录当前持有锁的线程。如果加锁的时候,该锁没有被其他线程获取,则计数器加1,当前线程设置为持有者线程。其他线程无法获得锁,会阻塞。如果再次加锁会确定该线程是否是持有者线程,如果是则计数器加一,否则不允许。当解锁的时候,计数器减去1,如果减为0,则当前线程释放锁,清除持有者线程的引用。
-
JVM内存分布,线程不安全的问题发生在哪快内存?
包括:程序计数器、Java虚拟机栈、本地方法栈、堆(用于存放对象实例和数组 )、方法区、运行时常量池、直接内存(直接内存并不是 JVM 内部的内存区域,而是通过 NIO 类库使用的一种直接操作系统内存的方式)。同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈
共享的区域会发生线程不安全的问题。
程序计数器:存放的是当前线程锁执行的字节码的行数
Java虚拟机栈:里面存放的是栈帧,栈帧里面存的是局部变量表,操作数栈等
本地方法栈:执行本地方法,Java调用非Java代码的接口
方法区:存储已经被虚拟机加载的信息、常量、静态变量等
堆:对象实例,数组,垃圾回收器管理的主要区域。
-
对象生命周期?
加载-连接(验证、准备、解析)-初始化-使用-垃圾回收-卸载
在加载阶段,类加载器从磁盘或者网络加载类的字节码文件,并将字节码文件转换为 Class 对象。
验证阶段:确保类的字节码文件符合 Java 虚拟机规范,以防止恶意代码的攻击。
准备阶段,Java 虚拟机为类的静态变量分配内存,并设置默认初始值 。
解析阶段,将符号引用替换为直接引用 ,以便运行时能够直接访问目标类、方法和字段。
在初始化阶段,Java 虚拟机执行类的初始化代码,包括执行静态变量的赋值和静态代码块的执行,初始化阶段是类加载过程的最后一个阶段
在使用阶段,程序通过创建对象、调用方法等方式使用类和对象
当对象不再被程序引用时,它会进入到不可达状态,表示它可以被垃圾回收器进行回收。
卸载(Unloading):在特定情况下,类加载器可能会卸载类,将类的字节码从方法区(或者元空间)中卸载,释放内存空间。
-
新生代为什么有两个S区?
主要是为了实现复制算法的垃圾回收方式。可以在复制算法中实现对象的老化机制,将存活时间较长的对象逐步移动到老年代,以减少每次垃圾回收时的复制开销。
新生代垃圾回收(minor GC)对象老化 老年代垃圾回收(major GC)
-
如何判断对象需要回收?
对象是否需要回收主要通过垃圾回收器来判断,主要通过可达性分析算法来判断对对象是否可达。不可达则回收。垃圾回收器定期扫描堆中的对象。
从一组称为 "GC Roots" 的根对象开始,递归地遍历所有引用链,标记所有被引用的对象为存活对象,然后将未被标记的对象视为垃圾对象,可以被回收
GC Roots 包括:
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中 JNI(Java Native Interface)引用的对象
-
OOM?
OOM(Out of Memory)是指程序在申请内存时,没有足够的内存可用,导致无法继续执行程序的运行。
堆内存溢出、栈内存溢出、永久代溢出、直接内存溢出、原空间溢出
解决OOM错误通常需要分析内存使用情况,找出内存泄漏的原因,并进行相应的优化或者调整。常见的解决方法包括增加堆内存大小、优化代码逻辑、释放不再使用的对象引用等。
-
redis数据结构?
Redis 是一种内存数据库,支持多种数据结构
字符串(string):可以存储字符串、整数或者二进制数据
列表(list):有序 字符串集合
哈希(hash):键值对的无序集合
集合(set):无重复的字符串集合
有序集合(zset):有序的集合(无重复)
-
redis分布式锁?过期怎么办?
通过 Redis 实现的一种**分布式锁机制,**它可以用于在分布式系统中实现多个进程或者线程之间的协作,确保在同一时间只有一个进程或者线程能够获得锁,从而保证共享资源的互斥访问 (setnx,1获取锁成功,0获取锁失败,del释放锁)
过期时间是为了防止锁未能正常释放而导致死锁。可以通过expire命令手动设置过期时间、使用lua脚本保证获取锁和设置过期时间的原子操作。设置合适的过期时间。使用带过期命令的setnx命令,直接设置锁的过期时间。
-
redis高可用的实现方式?
redis高可用是指redis在服务过程中,能够保持系统的持续稳定性和可用性。
可以采用
主从复制:设置一个主节点,多个从节点。主节点负责写和更新操作。从节点负责复制主节点的数据并进行读操作。主节点故障的时候,从节点升级为主节点。
哨兵模式:一种监控和管理redis实例的机制。可以监控主节点和从节点的状态。通常由多个哨兵节点组成
集群模式:分布式部署,多个redis节点组成一个集群,数据被分片存储到多个节点中,并通过哈希槽来管理数据的分布和路由。
持久化:RDB、AOF,通过持久化redis重启的时候恢复数据,保障数据不会丢失。
监控和警报:配置监控系统监控redis运行状态,出现异常的时候进行报警。
-
kafka组件
Kafka 是一种分布式流处理平台,它主要用于实时数据流处理,具有高吞吐量、低延迟、高可靠性等特点。主要组件有broker(服务器节点)、topic(消息的逻辑分类,类似不同的帖子,一个topic可能有多个分区)、consumer(消息消费者)、consumergroup、zookeeper、producer(消息产生者)、controller(管理分区leader选取,只有一个)。Kafka 使用 Zookeeper 来保证分布式协调和一致性
-
kafka如何保证消息的顺序
只能在单个分区内保证顺序,不能跨分区保证全局顺序 。单个分区内消息是有序的,按照消息产生者发送的顺序排序 。单个生产者将消息都发送到一个分区 。单个消费者只消费单个分区的消息 。消息时间戳排序,broker通过消息的时间戳对消息进行排序。 -
kafka遇到大量数据,消费者处理不过来怎么办?
增加消费者数量,优化消费者程序、水平扩展(消费者程序上进行水平扩展,部署多个消费者实例)。调整消费者配置。增加资源(服务器资源、CPU、内存、网络带宽)
-
spring如何解决循环依赖问题
通过三级缓存实现。分别用于存储正在创建的bean对象,已经创建完成但还没填充属性的bean对象和已经完全创建完成的对象。
实例化对象的时候发现循环依赖关系,之后会创建没有填充属性的bean对象,然后逐个填充bean的属性。填充过程中发现对方bean的属性还没填充完则先存储,等对方填充完之后再填充。当所有的bean对象都填充完之后,放入三级缓存中,并返回给调用者。
-
mybatis中$和#的区别?
$ 和 # 在 MyBatis 中的主要区别在于参数替换的方式:$ 是直接替换,不进行预编译,而 # 是占位符预编译,会将占位符替换为 ?,然后在执行 SQL 语句之前,使用预编译的方式设置参数的值。使用$会存在sql注入的风险。
-
linux常用命令
文件和目录操作:
ls:列出目录内容。
cd:切换当前目录。
pwd:显示当前工作目录。
mkdir:创建新目录。
cp:复制文件或目录。
mv:移动或重命名文件或目录。
rm:删除文件或目录。
系统信息:
top:显示系统中耗费 CPU 最多的进程。
free:显示系统内存使用情况。
df:显示磁盘空间使用情况。
uname:显示系统信息。
进程管理:
ps:显示当前运行的进程。
kill:发送信号给进程,用于终止进程。
killall:终止指定名称的所有进程。
pgrep:根据进程名搜索进程 ID。
pkill:根据进程名发送信号给进程。
权限管理:
chmod:修改文件或目录的权限。
chown:修改文件或目录的所有者和所属组。
chgrp:修改文件或目录的所属组。
网络操作:
ifconfig:显示和配置网络接口信息。
ping:测试主机之间的连通性。
nslookup:查询 DNS 信息。
wget:从网络下载文件。
scp:安全地复制文件到远程主机。
ssh:通过安全 Shell 登录到远程主机
压缩和解压缩:
tar:创建和解压 tar 归档文件。
gzip:压缩文件。
gunzip:解压缩文件。
-
linux下如何对一个日志进行查找?
grep命令:grep 命令用于在文件中搜索指定的模式
awk命令:awk 是一种文本处理工具,可以用于提取、处理和分析日志文件中的数据
sed命令:sed 是一个流编辑器,可以用于在文件中进行搜索和替换。例如,可以使用 sed 命令来替换日志文件中的文本
用 find 命令:find 命令可以用于在文件系统中搜索文件
使用 locate 命令:locate 命令用于快速定位文件。
-
MySQL的存储引擎?
innoDB:默认存储引擎,支持事务(ACID)、行级锁、外键约束等。高可靠和搞性能的特性。
myisam:具有较快的读取速度。但不支持事务、行级锁和外键约束,但支持全文索引、压缩表。使用于读取频率远远高于写入频率的应用。
CSV:将表数据存储在CSV文件中,适用于数据的导入和导出。不支持事务、索引等特性。
-
如何知道用了什么锁?
show engine innodb status查看innoDB引擎的状态信息。
检查是否包含死锁或者锁等待的情况。
-
explain的作用(分析查询语句,慢sql优化)
EXPLAIN 是 MySQL 中用于分析查询语句执行计划的关键字。通过分析 EXPLAIN 的输出结果,(包括id,select_type、table、type、key、key_len、extra、rows等)你可以了解到 MySQL 是如何执行查询语句的,以及是否可以进行优化,例如添加索引、修改查询语句等
explain来去查看这条sql的执行情况,比如在这里面可以通过key和key_len检
查是否命中了索引,如果本身已经添加了索引,也可以判断索引是否有失效
的情况
-
mysql分库分表
微服务,每一个服务需要一个数据库。
垂直分库分表:根据业务模块或数据特性将不同的表拆分到不同的数据库中
水平分库分表:将同一张表按照一定规则(如按照用户ID、时间等)拆分到多个数据库或多个表中。
一主多从复制:一个主库用于写入操作,然后配置多个从库用于读取操作。可以将读请求分发到不同的从库上,以减轻主库的压力。配置主从复制即可。
分片策略:将数据按照一定规则(如哈希、范围等)拆分到多个数据库或多个表中,每个分片独立存储一部分数据。
-
随机分库的时候,查询的时候如何知道去哪个数据库查?
哈希取模、一致性哈希、随机选择、负载均衡算法:轮询、随机、加权轮询、加权随机。
-
红黑树为什么能保持平衡?
红黑树的平衡指的是保持树的高度平衡,即保证任意路径上的黑色节点数量相等
节点的颜色规则:红黑树中的每个节点都被标记为红色或黑色,红黑树保证了从根节点到叶子节点的任意路径上,黑色节点的数量相等 。保证了红黑树的高度是平衡的,即所有叶子节点到根节点的路径长度相等。
旋转操作:在对红黑树进行插入和删除操作时,可能会破坏红黑树的平衡性。为了保持平衡,**红黑树通过进行旋转操作来重新调整树的结构。旋转操作包括左旋和右旋,**通过交换节点的位置来调整树的结构,从而保持红黑树的平衡性。
变色:在进行插入和删除操作时,可能会通过改变节点的颜色来保持红黑树的平衡
-
mysql底层如何执行sql的?
解析sql-优化查询计划-执行查询计划
sql解析:把sql语句进行解析,包括词法分析和语法分析。
查询优化:对查询语句进行优化,选择合适的索引 ,重写查询
生成执行计划:完成优化后,生成一个执行计划,可以通过explain查看
执行查询计划:根据生成的计划执行查询操作,存储引擎负责实际的数据访问和操作
返回结果:返回给客户端这个过程中涉及到了数据库引擎、索引、缓存、磁盘 IO 等多个方面的操作和优化。
-
orderby走不走索引,需要注意什么?
ORDER BY 子句通常是可以利用索引的,
如果 ORDER BY 子句中的字段与查询条件中的字段匹配,并且该字段上存在索引,那么 MySQL 可能会使用索引来加速排序操作。
如果查询中的所有字段都包含在某个索引中,并且 ORDER BY 子句中的字段也包含在该索引中,那么 MySQL 可能会使用覆盖索引来执行查询和排序操作,从而避免额外的排序操作。
如果 ORDER BY 子句中指定了 ASC(升序)或 DESC(降序),那么 MySQL 可能会根据索引的排序顺序进行优化。如果索引是按照相反的顺序进行排序,MySQL 可能无法直接使用该索引进行排序。
确保排序字段与查询条件匹配,并且尽可能使用覆盖索引。
注意索引的选择性和排序方向,以及字段在索引中的位置。
注意查询的性能和优化,根据具体情况选择合适的索引和排序策略
-
双重检查锁定的单例模式为什么要双重检查?
双重检查锁定(Double-Checked Locking)的单例模式是为了在多线程环境下保证单例对象的创建过程是线程安全的 ,并且在对象被创建后能够提供较好的性能。
减少同步块的使用:
在单例对象已经创建的情况下,不需要每次都进入同步块进行加锁和解锁操作 ,直接返回已经创建好的单例对象。这样可以减少同步块的使用,提高程序的性能
线程安全性:
在多线程环境下,如果不进行双重检查,在进入同步块之前没有进行检查,那么可能会导致多个线程同时进入同步块,从而创建多个单例对象。通过双重检查,可以保证只有一个线程进入同步块进行单例对象的实例化,其他线程在同步块外等待,避免了创建多个单例对象的问题
-
.java IO模型。select,poll,epoll底层是什么数据结构,为什么select限制1024而poll不限制,如何改进的
Java IO 模型指的是 Java 中用于进行输入输出操作的模型,它描述了程序与外部设备之间进行数据交换的方式和机制。常见的 Java IO 模型包括阻塞 IO、非阻塞 IO、多路复用 IO 和异步 IO
针对多路复用 IO,通常有以下几种选择:select、poll 和 epoll。这些技术都是用来处理多个文件描述符的就绪状态的,以提高 IO 操作的效率。
select:用一个数组来管理文件描述符,是fd_set。这个数组大小是固定的,通常为1024.因为select是基于位图结构的。
poll:使用动态数组来管理文件描述符。是pollfd。没有对数组大小限制。
epoll:采用红黑树(哈希表)来管理文件描述符。在查找和操作的时间复杂度是O(logn)。可以处理任意数量的文件描述符。
要改进 select 的限制,可以考虑增加 fd_set 的大小,但这样会增加系统资源的消耗,并且仍然无法完全解决数量限制的问题。因此,更好的选择是使用 poll 或 epoll 来替代 select,以提高系统的性能和扩展性。
-
数组为什么就是比链表遍历快
因为数组的内存是连续的,可以利用CPU缓存机制快速访问。CPU会将该元素所在的内存块一次性加载到缓存区。而链表是分散存储的。需要频繁的跳转内存地址。并且数组支持根据索引访问(寻址公式),链表是不支持的。
-
什么时候对象会到老年代?
取决于不同的垃圾回收算法和具体的JVM实现。年龄达到阈值(通常是15岁),可以通过参数来设置。当Survivor区空间不足的时候,会将部分对象今生到老年代。JVM可能将大对象直接分配到老年代,避免发生多次内存复制操作,这个阈值可以通过参数设置。
-
jvm优化调参命令
堆内存参数:
-Xms:设置堆内存的初始大小。
-Xmx:设置堆内存的最大大小。
垃圾回收参数:
-XX:+UseSerialGC:使用串行垃圾回收器。
-XX:+UseParallelGC:使用并行垃圾回收器。
-XX:+UseConcMarkSweepGC:使用CMS垃圾回收器。
-XX:+UseG1GC:使用G1垃圾回收器。
-XX:MaxGCPauseMillis=:设置垃圾回收的最大停顿时间。
堆外内存参数:
-XX:MaxDirectMemorySize=:设置堆外内存的最大大小。
线程参数:
-XX:MaxTenuringThreshold=:设置对象晋升到老年代的年龄阈值。
-XX:ThreadStackSize=:设置线程栈的大小。
其他参数:
-XX:+PrintGCDetails:打印详细的垃圾回收信息。
-XX:+PrintGCDateStamps:打印垃圾回收的时间戳。
-XX:+PrintHeapAtGC:在垃圾回收前后打印堆内存的情况
-
redis分布式锁实现方式以及可能出现的问题?
setnx命令设置分布式锁(设置一个键的值,键不存在,则设置成功,存在则失败,通过del释放锁),可以设置过期时间
set命令设置锁的过期时间,
redlock:redlock算法实现分布式锁。
redission:是第三方库,支持可重入锁、公平锁等。
可能会遇到死锁、锁的释放问题、性能问题、单点故障
-
从AOP角度说一下@Transaction可能失效的情况以及原因
Spring 的事务管理是基于 AOP 实现的 ,只有通过 Spring 代理对象调用被注解的方法时,事务才会生效。如果一个带有 @Transactional 注解的方法内部调用另一个带有 @Transactional 注解的方法,而调用方没有通过 Spring 的代理调用被调用方 ,那么事务可能不会生效。
Spring 只会对抛出到事务边界外部的异常进行事务回滚处理。如果一个带有 @Transactional 注解的方法内部发生了未捕获的 RuntimeException
如果一个带有 @Transactional 注解的方法内部抛出了编译时异常,并且被方法内部的 try-catch 块捕获了,那么事务可能不会生效
如果一个带有 @Transactional 注解的方法被声明为 private,那么事务可能不会生效 -
java是引用传递还是值传递
值传递的。在 Java 中,基本数据类型(如 int、double、boolean 等)是按值传递的,而对象引用(即对象的地址)也是按值传递的。虽然 Java 中的参数传递方式是值传递,**但对于对象引用来说,传递的是对象的地址值,所以在方法内部对对象的修改会影响原始对象。**这也是 Java 中常说的"对象传递"的原因。
-
explain分析的时候,type和extra出现什么内容表示不太优?
type:如果是index(索引树扫描)、all则表示全表扫描,性能最差。
extra:额外的优化建议。Using filesort:查询需要排序但无法使用索引进行排序时
Using temporary:查询需要创建临时表。Full scan on NULL key:引中包含 NULL 值,并且需要进行全表扫描时
-
多线程为什么会出现并发问题
多线程之间存在竞争关系,包括对资源的竞争,对数据的竞争。
出现死锁问题:两个线程都需要对方的资源,并且无法释放导致互相等待
内存可见性:内存可见性问题是指一个线程对共享变量的修改对其他线程不可见的情况。
-
AtomicInteger原理?
AtomicInteger 是 Java 中的原子整数类,它提供了一种线程安全的方式来对整数进行原子操作。在多线程环境下,使用 AtomicInteger 可以避免数据竞争和其他并发问题。
AtomicInteger 的原理主要基于 CPU 提供的原子指令(比如 CAS 指令)来实现原子操作
AtomicInteger 内部会利用 CAS 操作来实现诸如增加、减少、获取当前值等操作的原子性。这样一来,多个线程可以安全地同时对 AtomicInteger 进行操作,而不需要额外的同步措施(比如加锁)。
-
Java异常?
异常类是通过继承自 Throwable 类来实现的。Java 的异常类主要分为两种:Checked 异常和 Unchecked 异常(也称为运行时异常)。
Checked 异常是指在编译时必须进行处理的异常,如果不处理就会导致编译错误Checked 异常一般继承自 Exception 类,但不继承自 RuntimeException 类
Unchecked 异常(运行时异常)Unchecked 异常是指在编译时不强制要求进行处理的异常,程序可以选择处理也可以不处理。Unchecked 异常一般继承自RuntimeException 类,以及其子类 Error。
-
where和having的区别
WHERE 子句用于在 SQL 查询中指定条件来过滤行。它在查询的执行过程中对行进行筛选,只有满足指定条件的行才会被包含在结果集中
HAVING 子句用于在 SQL 查询中指定条件来过滤由 GROUP BY 子句生成的结果集中的分组。它通常与 GROUP BY 子句一起使用,用于对分组后的结果进行筛选。可以和聚合函数搭配。