Redis:
1、Redis常见的五种数据类型
答:有String(字符串),Hash(哈希表,一个key 对应一对 (field,value)),List(链表),set(无序集合),zset(有序集合)
2、Redis 持久化
答:Redis提供了两种持久化的机制,一种是RDB,一种是AOF。对于RDB,主要原理是使用快照文件,对Redis内存中的数据进行拷贝存到磁盘中,当Redis宕机后,可以读取磁盘中的快照文件来恢复数据。 对于AOF,主要原理是一个日志追加文件,把redis的写命令都写进日志文件中,当宕机后需要恢复数据,可以执行一遍上述日志文件的redis命令来恢复数据。
3、Redis的淘汰策略机制
答:淘汰策略主要有八种:不做处理,淘汰有TTL中最小TTL的那个,随机淘汰(两种,所有和只有TTL的),LRU(两种),LFU(两种)
4. Redis为什么快?
答:因为Redis的数据是存放在内存的,访问内存 会比访问外存更快。并且Redis是单线程的,避免了上下文的切换操作。
MySQL:
1.事务的特性?
答:事务的特性有四个,原子性、一致性、隔离性、持久性。
2.undo log 和 redo log的区别?
答: undo log 主要是记录一些逆操作,用来恢复数据,保证数据的原子性和一致性,比如当数据库执行了一条insert命令,undo log 就会记录一条delete命令。
redo log 主要是记录数据的物理变化,服务宕机重启后可以用来同步数据
3.两种存储引擎?
4.索引?
5.锁机制
6.MVCC的原理
SSM + Springboot + SpringCloud
1.什么是IOC?
2.什么是AOP?
3.Bean的生命周期
4.循环依赖?
5.自动配置原理?
RabbitMQ
1.如何解决消息丢失问题?
答:要看是哪种消息丢失问题,因为消息是由生产者发送到交换机上,然后交换机发送到指定的消息队列上,消费者再从消息队列中拿出消息进行消费。这里统一做法是加ACK确认,每一个环节,当发送成功后,都要发送一个确认收到的ACK。
2.如何解决重复消费问题?
答:对每个业务消息绑定一个id标识,当消费后,把记录写进数据库,下次再对其进行消费时,查询一下数据库,判断这个消息是否消费过即可。
多线程
1.线程和进程的区别?
进程就是内存中运行的应用程序,每个进程都有自己独立的内存空间,一个进程有多个线程
线程就是进程中的一个控制单元,多个线程共享一个内存空间,一个进程可以运行多个线程
2.并行和并发的区别?
并行是同一个时间点做多件事,并发是同一个时间段做多件事。
3.线程创建的方式有哪些?
共有四种方式,1.继承Thread类,重写run方法。
2.实现Runnable接口,重写Runable的run方法,再使用Thread的构造函数把Runable实现类作为参数传入创建一个线程。
3.实现Callable接口,通过futureTask包装 Callable对象,再将futureTask作为对象传入Thread的构造函数,创建线程
4.通过线程池获取。
4.线程的start和run的区别是什么?
start用于启动线程,run用于执行线程,
start只能调用一次,run可以调用多次
start是用来使线程进入就绪状态,当分配到时间片时便会执行,如果直接运行
run方法,则相当于只是执行了Thread中的一个普通方法并不会启动线程。
简单来说,Start方法会执行线程前相对应的准备工作。
5.sleep和wait的区别
两者都可以使线程进入等待状态、但是sleep是属于Thread类、wait是属于object类
sleep不释放锁、wait释放锁
wait()用完后,线程不会自动执行,必须调用notify()或notifyAll()方法才能执行,
sleep()方法调用后,线程经过过一定时间会自动苏醒,wait(参数)也可以传参数使
其苏醒
6. notify 和notifyAll的区别
notify: 唤醒一个处于等待状态的进程,如果多线程在等待则需要看看优先级
notifyAll:唤醒所有处于等待状态的线程,让他们去竞争一个锁,谁竞争到
就先进入就绪状态
7. 什么是线程死锁:
死锁就是不同的线程在执行过程中都不放弃自己的资源,都在等着对方先释放资源,
这样便形成了死锁
8.如何停止一个正在运行的线程
1.stop方法
2.interrupt中断线程
3.run方法执行结束则会自动退出
4.变量标记法
9.yield:
可以让出cpu的使用权,是当前线程从运行状态转为就绪状态,等待cpu的下次调度,注意,yield是让出CPU使用权,但是不会释放锁等资源。
10.yield和 sleep的区别
yield是让线程从运行状态转为就绪状态,而sleep是从运行状态变为等待状态,即被阻塞了,两者的共同点是:都不会释放锁,不同点是:除了状态转换不同,还有sleep需要处理中断异常,而yield不需要。
11.JMM (Java内存模型)
JMM (Java内存模型) 定义了共享内存中多线程程序读写操作的行为规范,JMM把内存分为两块,一块是私有线程的工作内存(每个线程的工作内存是相互隔离独立的),一块是所有线程的共享区域(主内存)。
线程和线程之间是相互隔离的,线程和线程交互需要通过主内存。
12.你谈谈对CAS的理解。
CAS(比较再交换)体现是一种乐观锁的思想,在无锁状态下保证线程操作数据的原子性(自旋锁)。
13. 谈谈对volatile的理解。
1.实现多线程情况,线程修改共享变量后对其他线程的可见性。
用volatile 修饰共享变量,能够防止编译器等优化发生,让一个线程对共享变量的修改对另一个线程可见。
2.禁止对共享变量的指令重排序。
用volatile修饰共享变量会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果。
写操作加入屏障,可以防止其他写操作往下走
读操作加入屏幕,可以防止其他读操作往上走
如果是写操作的变量,尽量放到最后
如果是读操作的变量,尽量放到最前
14.什么是AQS?
是多线程中的队列同步器,是一种锁机制,它是作为一个基础框架使用的,像ReentrantLock都是基于AQS实现的。
AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程
在AQS内部有一个state属性,相当于一个锁资源,默认是0(无锁),如果队列中有一个线程修改成功了state为1,则当前线程就相当于获得了资源。
在对state的修改,为保证原子性采用的CAS机制。
15.synchronized 和 Lock 的区别
1.synchronized 是 关键字,源码在JVM中,用C ++ 语言实现,Lock是个接口,用Java实现
2.两者都属于悲观锁,synchronized 在退出同步代码块后自动释放,而Lock需要手动调用 unlock方法释放。
3.Lock的功能更全面,提供了公平锁、可打断、可超时、多条件变量,在没有竞争时,synchronized性能不赖,在竞争激烈时,Lock的实现通常有更好的性能。
16.如何进行死锁诊断?
在命令行使用jps可以查看 死锁的进程id,然后通过 jstack -L 进程id 即可查看死锁的日志
17.聊一下ConcurrentHashMap
底层数据结构 跟 HashMap一致,jdk1.7之前是 数组 + 链表, jdk8 之后是数组 + 链表 + 红黑树
加锁的方式:
jdk1.7之前,是基于Segment进行分段加锁的,一个Segment对应多个HashEntry节点,当需要修改时,会在Segment 采用加锁的方式,锁住多个节点,只允许一个线程访问修改。
jdk8 之后,是基于HashEntry 的首节点进行加锁,加锁粗粒度更细,比起jdk7,能更好的提高并发效率。
18.线程池中有哪些常见的阻塞队列?
最常见的是LinkBlockingQueue和ArrayBlockingQueue,
两者有一定区别,LinkBlocking 底层是基于链表,而ArrayBlockingQueue底层是基于数组
LinkBlocking 的长度可有界也可无界,而ArrayBlockingQueue是强制有界,在创建的时候必须指定。
LinkBlocking 只有在添加数据的时候才会创建节点,而ArrayBlockingQueue是提前初始化好了的
LinkBlocking 底层是基于两把锁(头和尾),而ArrayBlockingQueue是一把
所以相对来说,LinkBlocking性能更高一点。
19.如何确定核心线程数
对于高并发、执行时间短的,一般设置为CPU的核数 +1,减少线程上下文的切换
并发不高,但执行时间长的,分为两类,一类是IO密集型的任务,一般设置为CPU核数 * 2 + 1 ,因为占用CPU时间短,一类是计算型任务,一般设置为CPU核数 + 1 ,因为经常占用CPU。
20.说一下线程池的核心参数和线程池的执行原理
线程池有七个核心参数,分别是:
线程池核心线程数量
线程池最大线程数量 (核心线程数量 + 临时线程数量)
临时线程存活时间
临时线程存活时间单位
阻塞队列
线程工厂
线程拒绝策略
线程池的执行原理:
当提交一个任务到线程池中,若有空闲的核心线程,则执行任务,如果没有空闲的核心线程,则加入到阻塞队列中,若阻塞队列满了,则会创建临时线程去执行刚提交的任务,若核心线程和临时线程均在忙碌且阻塞队列满了,则会触发拒绝策略,拒绝策略有四种:1.直接抛出异常。2.让主线程去执行。3.丢弃阻塞队列中等待最久的任务,把新提交的任务加入到队列中。4.直接丢弃新提交的任务。
21.线程池的种类有哪些?
1.固定核心线程数的线程池 (newFixedThreadPool)(不含临时线程,阻塞队列无界 为 LinkedBlockingQueue)
即核心线程数 和最大线程数一样,阻塞队列为LinkedBlockingQueue,最大容量为Integer的最大值
适用于任务量已知,相对耗时的任务
2. 单线程化的线程池 (newSingleThreadExecutor),它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO 先进先出)执行
核心线程数和最大线程数都是1,阻塞队列为LinkedBlockingQueue,最大容量无界
适用于需要按照顺序执行的任务
3.可缓存线程池 (newCachedThreadPool)
核心线程数是0
最大线程数是 Integer的最大值
阻塞队列为 SynchronousQueue,即不存储元素的阻塞队列
适合任务数比较密集,但每个任务执行时间短的情况
4. 可以执行延迟任务的线程池,支持定时以及周期性执行(newScheduledThreadPool)
22. 为什么不建议使用Executors创建线程池?
Executors创建的线程池,大多会出现OOM问题,即内存溢出,因为创建的一些线程池中的阻塞队列是无界的,会造成资源的浪费。
而使用 new ThreadPoolExecutors创建的线程池,是自定义线程池参数的,所以可以根据自己的业务需求去制定规则,更加灵活。
集合
JVM
计算机网络
操作系统