常见面试题

hashmap

存储过程

sql优化

线程池中提交一个任务的流程是怎样的?

线程池有五种状态

如何优雅的停止一个线程?

线程池的核心线程数、最大线程数该如何设置?

对线程池负责执行的任务分为三种情况

如何理解Java并发中的可见性、原子性、有序性?

Java死锁如何避免?

Redis持久化机制

 

 

 

Redis 缓存雪崩、穿透、击穿 

1.缓存有效时间的设置

2.查到数据时,重新将这个值设置进去,也就是更新缓存有效时间

3.查询数据库方面添加对应的锁

1.缓存有效时间设置方面

2.redis集群方面采用更稳定的架构

1.布隆过滤器

2.参数的校验

3.查询数据库方面添加对应的锁

Redis 数据类型 

说一说Redis的过期策略和内存淘汰策略

为什么Redis这么快?

1.基于内存操作

2.单线程,减少线程上下文切换,性能开销及锁

3.IO多路复用epoll

4.内部数据结构

Spring的事务隔离级别 

数据库事务

cup飚高,怎么处理

首先,CPU是整个电脑的核心计算资源,对于一个应用程序来说,CPU的最小执行单元是线程,导致CPU标高的原因有几个方面?

第一个是CPU的上下文切换过多,对于CPU来说,同一个时刻,每个CPU核心只能运行一个线程,如果有多个线程要去被执行怎么办呢,CPU只能通过上下文切换的方式,来执行调度不同的线程,上下文切换需要做两个事情。第一个是保存运行中线程的执行状态,第二个让处于等待中的线程恢复执行,这两个过程需要CPU执行内核相关指令,去实现状态的保存和恢复,如果较多的上下文切换,会占据大量CPU的资源,从而使得CPU无法去执行用户进程中的真正指令,导致响应速度下降,在JAVA中文件io,网络io,锁等待这些都会去造成线程阻塞,而线程阻塞就会导致CPU的上下文切换,

第二,CPU资源过度消耗,也就是有线程一直占据CPU资源,无法被释放,比如说死循环,CPU利用率过高之后。导致应用程序中的线程。无法去获得CPU的调度,从而影响程序的执行效率,

所以这两个问题导致CPU利用率较高,我们可以通过top命令,找到CPU利用率较高的进程,再通过shift+h找到进程中CPU消耗过高的线程,这里呢有两种情况。

第一个CPU利用率过高的线程一直是同一个线程,也就是线程ID没有变化,说明在程序中存在长期占用CPU没有释放的情况,那么这种情况可以直接通过jstack获得线程的Dump日志。定位到线程日志后,就可以找到问题的代码,

第二个是CPU利用率过高的线程ID一直在不断变化,那么。说明线程创建过多,需要去挑选几个线程ID。通过jstak去线程dump中去进行排查,最后有可能定位的结果是程序正常,只是在CPU飙高的那一时刻,用户访问量非常大,导致系统资源不够,那么这个时候我们需要采取的手段去增加系统资源。

mybatis中#{}和${}的区别是什么?

线程安全的理解

解释线程安全

线程安全的具体表现

原子性,有序性,可见性解释和导致这一现象的原因及解决方案

导致线程安全最主要的原因

简单来说,在多个线程去访问某个方法或者对象的时候,不管通过任何的方式的调用或者线程如何去交替执行,在程序中不做任何同步干预的情况下,这个方法或者对象的执行结果都能够按照预期的来反馈,那么这个类我们认为它是线程安全的,

实际上线程安全问题的具体表现它有三个方面,原子性,有序性和可见性:

原子性就是说一个线程执行的一系列程序指令操作的时候,它应该是不可中断的,因为一旦出现了中断,站在多线程这样一个角度来看,这1系列的程序指令会出现前后执行结果不一致的问题,而CPU的上下文切换是导致原子性问题的一个核心,而Jvm中提供了一个Synchronized关键字来去解决这样一个问题,

可见性就是说在多线的环境下,由于读和写是发生在不同的线程里面的,有可能会出现某个线程对共享变量的修改对其他线程不是实时可见的,导致可见性问题的原因有很多,比如说像CPU的高速缓存,CPU的指令重排序,编译器的指令重排序

有序性就是说程序编写的指令顺序和最终CPU运行的指令顺序可能会出现不一致的这样一个现象,这个现象称为指令重排序,所以有序性也会导致可见性的这样一个问题,可见性和有序性可以通过volatile关键字来解决,

在我看来导致有序性,原子性和可见性问题的一个本质是计算机工程师为了最大化的提升CPU利率导致的,比如说为了提升CPU的利用率,设计了三级缓存,StoreBuffer,缓存行的预读机制,在操作系统里面设计的线程模型,在编译器里面设计的编译器的深度优化机制,以上呢就是我对这样一个问题的理解

什么是双亲委派

类的加载过程

涉及到的加载器及加载的目录

双亲委派机制的作用

关于这个问题,首先简单说一下类的加载过程,类的加载过程就是我们自己写的JAVA文件到最终运行,它必须要经过编译和类加载这两个阶段,而编译的过程就是把.java文件编译成.class文件,而类的加载过程就是把class文件加载到jvm的内存里面,装载完成以后会得到一个class对象,我们就可以使用new关键字来实例化这个对象,

而类的加载过程需要涉及到类加载器,JVM在运行的时候会产生三个类加载器,这三个类加载器组成了一个层级关系,每一个类加载器分别去加载不同作用范围的jar包,比如说像bootstrapclassloader,它主要是负责JAVA核心类库的加载,也就是java_ home下面lib下的jar包,

extensionclassloader的主要是负责加载ext目录下的一个jar包

applicationclassloader的主要是负责当前应用里面classpath下面的所有jar包

除了系统自己提供的加载器外,还可以通过实现classloader来实现自定义类加载器去满足一些特殊的场景需求

而所谓的双亲委托模型就是至底向上查找,至顶向下加载,比如说当我们需要加载一个class文件的时候,首先会去把这个class文件的查询和加载委派给父加载器执行,如果父加载器都无法加载,那么在尝试自己的加载这个class,

那么这样的好处我认为有两个,第一个是安全性,因为这种承接关系实际上代表的是一种优先级,也就是说所有的类加载优先要给到bootstrapclassloader,那么对于核心类库中的一些类就没有办法被破坏,比如说自己写一个java.lang.string,最终还是会交给启动类加载器,再加上每个类加载器的本身的一个作用范围,那么自己写的java.lang.string就没有办法去覆盖类库中的类,第二个我认为这种层级关系的设计,可以避免重复加载导致程序混乱的一些问题,因为如果父加载器已经加载过了,那么子类加载器就没有必要再去加载了。以上就是我对这个问题的理解

什么是聚集索引和非聚集索引

简单来说,聚集索引呢就是基于组件创建的索引,除了主机索引以外的其他索引统一称为非聚集索引,也叫2级索引。因为在印度b的擎里面呢,一张表的数据对应的物理文件本身就是按照b加速来组织的,而具体索引呢就是按照每张表的组件来构建这样一个加数,然后电子节的里面存储了这个表里面的每一行数据记录,所以基于udp c这个特征呢,聚集索引并不仅仅是一种索引类型,还代表了一种数据的存储方式,同时也意味着每个表里面必须要有一个组件,如果没有组件会默认选择或者添加一个隐藏列作为主键索引来存储这个表的数据行,一般情况是建议使用至尊ID作为主键,这的ID本身是具有连续性,使得对应的数据也会按照顺序存储在磁盘上,写入性能和解锁性能都很高,否的话,如果使用UI的手机ID,那么在频繁的插入数据的时候,就会导致随机磁盘io,从而会导致性能下降,不过需要注意的是呢音乐APP里面只能存在一个最集中,所以原因很简单,如果存在多个区域索引,那么意味着这个表里面的数据会存在多个副本,不仅会造成磁盘空间浪费,还会去导致数据的维护困难,因为在印度APP里面的组件索引,它是存储了一个表的完整数据,所以如果是基于非聚集索引来查询一下数据的时候,那么最终还是得需要访问组件索引来进行解锁以上就是我对这个问题的理解这个问题要回答的好呢还真不容易

对象头会包含哪些信息

分布式锁有什么作用?如何实现分布式锁?

分布式锁是一种跨进程,跨机器节点的一种互斥锁,它可以用来去保证在多个机器节点,对共享资源访问的一个排他性。

分布式锁和线程锁的本质上是一样的,线程锁的生命周期是单进程多线程,而分布式锁的生命周期是多进程多机器节点,在本质上他们都需要满足,锁的几个基本的重要特征,排他性,也就是说在同一时刻,只能有一个节点去访问共享资源,其次就是可重入性,他允许一个已经获得锁的线程在没有释放锁之前,重新去获得锁,第三个是锁的获取和释放的方法,第4个是锁的失效机制,也就是说避免死锁的一个问题,所以我认为只要能够去满足这些特征的技术组件,都能够去实现分布式锁,

首先第一个是关系型数据库,它可以使用到唯一的约束,来去实现锁的排他性,如果要针对某个方法加锁,就可以去创建个表,去包含方法名称的一个字段,并且把方法名称这样的一个字段,设置成唯一的约束,那么抢占所的逻辑就会变成了往表里面去插入一条数据,如果已经有其他的线程获得了某个方法的锁,那么这个时候再去插入数据的时候,一定会失败,所以从而去保证了所的互斥性,那么这种方式虽然看起来很简单,但是实现比较完整的分布式锁,还需要考虑到重入性,锁的失效机制,没有抢占到锁的线程要等待阻塞,等等都会比较麻烦,

所以第二个就是Rides,它里面提供了setnx命令。去实现锁的排他性,当key不存在的时候就返回1,存在就会返回0,然后还可以使用expire命令。去设置锁的失效时间,从而去避免死锁的问题,当然有可能存在锁过期了,但是业务逻辑还没有执行完,所以这种情况下,我们可以写个定时任务,对指定的key去进行续期,Redission这个开源组件,他提供了一个分布式锁的封装实现,并且内置了一个Watchdog的机制,来对key去做续期,所以我认为redis里面这种分布式所的设计,已经能够去解决99%的问题了,当然如果在redis搭建了,高可用集群的情况下,去实现主从切换导致key失效的问题,也可能会导致多个线程或进程,抢占同一个群资源的情况,所以redis官方也提供了一个叫redlock的解决办法,

但是实际上会相对复杂一点,所以在我看来分布式锁它应该是一个cp模型,而redis是一个ap模型,所以在集群架构下,由于数据的一致性问题导致,极端情况下出现的,多线程或多进程抢占锁的情况,很难避免,

那么基于cp模型又能实现分布式锁特性的组件,主要是有Zookeeper或etcd,

首先在数据一致性方面,Zookeeper用到了zab协议,去保证了数据的一致性。etcd用到了Raft算法去保证数据一致性,

第二个是在锁的互斥方面,Zookeeper 它可以基于有序节点,再结合watch机制,去实现互斥和唤醒,而etcd。它也可以基于prefix机制和wat ch机制来实现互斥和唤醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值