Interview

CopyOnWriteArrayListjava

 

了解写时复制机制、了解其适用场景、思考为何没有ConcurrentArrayListredis

      内部持有一个ReentrantLock的可冲入锁,在增长、删除是加锁,使用try finally来在finally的最后语句块当中解锁,在增长、删除时候复制出来一个新的数组,来完成增长、删除的操做,提升查询的效率,查询的时候查询原来的数组,操做完成后将新数组的引用,赋值给原来的引用。底层数组使用volatile transient修饰的数组,采用volatile transient修饰的缘由,用transient修饰的数据不会被序列化,对于volatile,从java内存模型的角度,每一个线程都有本身的工做内存,处理数据时候获取中内存数据的拷贝,volatile修饰以后,就禁止了这种拷贝,直接获取主内存,保证的指令可见性,而不是数据的可见性,还会禁止jvm底层对数据的重排序,使用场景,好比说CopyOnArrayList的成员变量,这种状况有多个线程并发同时访问的变量,并且既不是常量,也没有在synchronzed()的同步代码块中。CopyOnArrayList的使用场景:适用于读多写少的并发场景。为何没有ConcurrentArrayList这样的数据结构?由于保证线程安全会有各类各样的手段,可是在保证线程安全的前提下,还要保证性能瓶颈,这就很难了,对于List这样的数据结构是作不到的,好比说在contains()这样的方法中,遍历的时候必定要锁住整个list的,采用分段锁也不合适,总不能数组有多少长度就用多少个分段锁吧,concurrentHahsMap的分段锁一旦肯定后,即时数组扩容,也不会变了。即时线程安全的CopyOnArrayList也只规避了读操做的并发瓶颈。算法

ConcurrentHashMapspring

了解实现原理、扩容时作的优化、与HashTable对比。数据库

  concurrentHashMap是基于分段锁来实现的,默认是16,有一个参数叫作concurrentLevel,该值说明有多少个分段锁,segment继承自ReentrantLock,1.8采用cas来实现避免加锁提升性能,只有内存值与当前值一致,才会修改为功。Cas是乐观锁,synchronized等等都是悲观锁。Cas有一个问题,会产生ABA的问题,好比线程A B都从内存当中取了值,这是线程2修改了值,作了一些操做有把值修改回去了,这时候线程1cas仍是成功的,可是线程2的操做就被忽略了,因此能够考虑加版本号,修改时除了比较当前值还要校验版本号。HashTable是直接在方法上的synchronized来保证安全的,并发是会有性能瓶颈的。扩容时候的优化能够考虑从避免rehash来回答。新建数组为原来长度的一倍,把原来的数据遍历放进来。数组

常见问题缓存

  • ConcurrentHashMap是如何在保证并发安全的同时提升性能?

使用细粒度的锁分段锁来实现线程安全、以及CAS来保证线程安全,不会有性能并发瓶颈。安全

  • ConcurrentHashMap是如何让多线程同时参与扩容?

数组链表加红黑树,以前是头插,如今是尾插,链表的最后一个数据的next为null,并发扩容不会next不会产生死循环。优化角度避免重复hash。服务器

  • LinkedBlockingQueue、DelayQueue是如何实现的?

前者基于链表、后者基于优先级队列。数据结构

  • CopyOnWriteArrayList是如何保证线程安全的?

新增、修改、删除,复制一个数组来完成操做,完成后指向原来的引用,读操做不会影响性能瓶颈。ReentrantLock可冲入锁。

ThreadLocal

了解ThreadLocal使用场景和内部实现

  ThreadLocal的内部实现:ThreadLocal底层是有静态内部类ThreadLocalMap来实现的,ThreadLocal有一个静态内部类叫作ThreadLocalMap,ThreadLocalMap有一个静态内部类叫作Entry,entry是弱引用机制的,entry有一个属性是value,存储数据,key是当前threadLocal对象,Thread持有ThreadLocalMap引用。每一个线程保存变量的副本。

  使用场景:某次请求,同一个线程下数据的传递,不然只能靠方法的返回值,解耦操做。在某些框架上,若是不用threadLocal,会有耦合的问题。还能够透传全局上下文,经过设置Thread构造函数的最后一个参数initThreadLocal,设置为true。

  缺点:线程池服用Thread对象,会有脏数据的问题,static 修饰会有内存溢出的问题,原本entry实现弱引用,想要经过GC来回收,value,static修饰方法区当中会有引用,致使没法回收。解决办法:remove()。

  解决线上日志上那台服务器上去找?

  ThreadLocal存储当前请求的traceID,根据id去找对应的日志文件。Value存IP。

ThreadPoolExecutor

了解线程池的工做原理以及几个重要参数的设置

1:核心线程数:若是为0,线程结束后全部线程都会被销毁。若是不为0,假设是n,会保留n个线程做为核心线程。

2:最大线程数:线程池中最多有当前数量的并发线程。

3:阻塞队列:LinkedBlockQueue,存储待执行的任务,使用锁来保证入队出队的原子性。

4:超时时间:多长时间回收空闲线程。核心线程默认是不会被回收的,有一个参数叫作容许核心线程超时设置为true,就能够回收了。

5:时间单位:时间单位

6:线程工厂:

7:拒绝策略:

l  丢弃任务,抛出异常(默认)

l  丢弃任务

l  丢弃最近最少使用的任务最久的

l  调用任务的run方法绕过线程池执行

 

线程池有几种类型:

new FixedThreadPool()建立固定大小的线程池

new singleThreadExecutor()建立单个线程池

new ScheduledThreadPool()建立可调度的线程池

new CheThreadPool()可伸缩的线程池

new WorkStealingPool() jdk8新出的

原理:主要是execute()、addWork()这两个方法:

Execute执行任务,addWork()是用来建立线程,内部由32位的二进制数来表示,高三位表示线程池的状态,一共有五种状态,runnable:能够接受任务,shutdown:不能接受任务,能够执行正在处理任务stop:不能接受任务,中止正在执行的任务。Tyding:全部任务都已被终止Terminated:已经清理完现场。首先会判断线程数是否小于核心线程数,若是是,建立线程。不然判断线程池是不是runnable状态,若是是置于队列,不是从队列移除。

  • 说一说往线程池里提交一个任务会发生什么?

Execute方法的执行流程,先判断工做线程数是否大于核心线程数,若是没有,那么就建立线程,不然判断线程是不是可运行状态,放到阻塞队列中。若是不是从阻塞队列中删除。在不知足可运行状态、或者缓存满了,达到了最大线程数,执行拒绝策略。

  • 线程池的几个参数如何设置?
  • 线程池的非核心线程何时会被释放?

达到空闲时间以后会被回收

任务执行完成以后,会设置空闲时间,到时间以后回收。

  • 如何排查死锁?

引用

了解Java中的软引用、弱引用、虚引用的适用场景以及释放机制

强引用:不会被在可以被根节点可达的状况下,不会被回收。Object object = new Object();即时系统立刻OOM了,也不会被回收。

软引用:有这样一个类,softRefferrence来定义,在系统OOM以前会被回收。适用于缓存,或者服务器计算的中间结果。

弱引用:YGC年轻代GC时会被回收,有WeakReferrence来调用,在引用的对象置为null时,能够主动断开链接,这是弱引用的使命。

虚引用:每一种引用都有一个对应的类来描述,定义以后就没法指向获取引用的对象。设置虚引用的目的是为了回收是获取一个系统通知。

常见问题

  • 软引用何时会被释放

OOM

  • 弱引用何时会被释放

YGC,当引用的对象设置为null,会自动断开引用

类加载

了解双亲委派机制

加载一个类时候,判断父类有没有加载,若是父类加载过了,就无需加载。若是没有加载,而且加载不了,就委托子类加载。

常见问题

  • 双亲委派机制的做用?

避免重复加载类,在内存中有不少重复类的字节码,因此有父类加载优先加载,若是已经加载过了,子类就不能再加载了。防止内存中字节码爆炸。自定义的类加载器加载的特定位置的类,自定义类加载器加载特殊位置的类。

  • Tomcat的classloader结构
  • 如何本身实现一个classloader打破双亲委派

  继承classloader,重写findclass方法,找到自定义目录下的文件,生成二进制流,调用defineClass()生成Class。何时须要自定义加载器?好比扩展加载源,好比数据库的驱动,系统自带的类加载确定没法加载。

jvm

 

GC

 

垃圾回收基本原理、几种常见的垃圾回收器的特性、重点了解CMS(或G1)以及一些重要的参数

 

内存区域

 

能说清jvm的内存划分

 

Jvm的体系划分:

 

本地方法栈:

 

封装的须要调用的本地方法,好比System.currentMillions()

 

虚拟栈:

 

方法的执行就是栈帧入栈出栈的过程,正在执行的方法就是栈顶的栈帧。

 

操做变量表:相似于槽,存储标识地几个变量的值。存储方法的局部变量,参数,没有准备阶段,因此必需要立刻初始化。

 

操做数栈:压栈入栈去作计算

 

动态连接:栈帧当中包含对常量池的引用。

 

方法出口:方法的返回值,包括正常返回,异常返回

 

堆:年轻代老年代。Eden survior1 surviior2 8:1:1。新建立的对象分配在Eden中,若是满了会触发YGC,把活着的对象放到未使用的输入survior中,每一个对象都有一个计数器,每经历一次YGC,就加1,默认达到15次,就放到老年代。MaxTuringThreshold默认15次。若是一个对象elden区放不下,就会YGC,还放不下,就会放到老年代,还放不下,就会FULL GC,还放不下,就会报错。OOM。String字符串常量是在堆中。

 

程序计数器:CPU时间片切换到执行的不一样线程,等在回到记录上一个线程执行的位置。

 

元数据区:方法信息、静态属性,常量,类信息、常量池

 

常见问题

 

  • CMS GC回收分为哪几个阶段?分别作了什么事情?

 

Cms利用三种颜色来完成标记。黑:可以被GCroot直接找到的没有引用白色节点的。白色:须要回收的对象。灰色:可以被GCroot可达,可是没有扫描完成的。

 

Cms有四个阶段:

 

a)          初始标记:从GCroot出发,找到全部直接引用的节点。Stw

 

b)          并发标记:以上一阶段的节点为根节点,并发遍历标记。Stw

 

c)           从新标记:并发标记GCroot可能有引用关系的变化,因此须要从新标记。从根节点,GCroot遍历,从新标记。

 

d)          并发清理:并发清理全部对象。标记清理:会有空间碎片的问题。

 

回收的原则:浮动垃圾,以前有引用,如今没有引用了,发现不了,回收原则:可达的对象绝对不能回收,能够有垃圾没有回收。

 

  • CMS有哪些重要参数?

 

1:老年代使用率达到某个阈值,开启fullGC。

 

2:执行了多少次的不压缩的full gc 来一次压缩的full gc。

 

  • Concurrent Model Failure和ParNew promotion failed什么状况下会发生?

 

  ConcurrentModelFilure:有大量对象从elden升级到老年代,老年代放不下,报的错误。解决办法:开启串行老年代收集器,回收整个老年代。

 

  ParNew promotion failed:晋升担保失败:空间碎片的问题,来一次标记整理算法回收。

 

  • CMS的优缺点?

 

缺点:有空间碎片化的问题,这是须要内存整理

 

优势:减小stw的次数。配置执行了多少次的full gc,采起作内存整理。

 

 

 

  • 有作过哪些GC调优?

 

好比说:设置jvm的启动参数:XMS XMX最小堆内存与最大堆内存,设置成同样的大小,不然服务器会不断地收缩与扩容,增长系统的压力。调节elden区域surior区的交换次数参数,maxTurningThreshold,将年轻代的转为老年代。或者配置参数UseG1Gc启动新的G1垃圾回收器。

 

  • 为何要划分红年轻代和老年代?

 

对象的声明周期不一样。

 

  • 年轻代为何被划分红eden、survivor区域?

 

采用复制算法回收,须要额外得存储区域作担保。

 

  • 年轻代为何采用的是复制算法?

 

须要频繁的作对象的建立于回收,对象声明周期较短。

 

  • 老年代为何采用的是标记清除、标记整理算法

 

老年代声明周期比较长,若是采用复制算法须要其余内存做担保,保留存活的对象。年轻代老年代分配比例是3:8。

 

  • 什么状况下使用堆外内存?要注意些什么?

 

对外内存:java.nio.DirectorByteBuffer分配的内存是堆外内存,优势:提升io效率。缺点:堆外内存回收相对堆外内存来讲耗时间。底层:unsafe.allocateMemory()来分配。每个DirctorByteBuffer初始化都会有一个Cleaner对象调用cleaner()来回收。

 

  • 堆外内存如何被回收?
  • jvm内存区域划分是怎样的?

spring

 

  bean的生命周期、循环依赖问题、spring cloud(如项目中有用过)、AOP的实现、spring事务传播

 

循环依赖问题:

 

  好比说spring当中的自动装配,A依赖了B,B依赖了A,这个时候在实例化A类的这个对象时候,须要依赖B,A没法实例化,在实例化B的对象时候,依赖了A对象,B对象也没法完成实例化,须要在AutowiredBeanPostProcessor后置处理器中完成属性的注入。

 

  Spring是这样处理的,他设计了一级缓存,已经实例化单例对象的缓存、二级缓存,正在建立中的对象的缓存、三级缓存,单例对象工厂的缓存,这样的map,在refresh()方法当中,倒数第二个方法实例化bean,首先实例化时候从一级缓存中获取,以及缓存存储已经实例化完成的单例对象,若是没有,从二级缓存中获取,二级缓存存储的是正在建立中的对象,二级缓存若是没有,有一个暴露对象的参数,true,能够从三级缓存中获取,这个时候是有的。就能够经过AutowiredBeanPostProcessor自动装配的后置处理器干扰bean的实例化过程。

  • spring事务传播

当前没有事务,建立事务,有事务,就加入到这个事务中来等等。

或者就直接新建事务。

  • spring中bean的生命周期是怎样的?

Spring当中完整的bean的声明周期,从构造函数初始化开始,实例化一个AnnotationConfigApplicationContext开始,接下来就能够从容器中获取bean,说明,在构造函数当中就已经完成了spring当中的bean的初始化,以及准备spring的环境。首先会调用this()函数,初始化defaultListableBeanFactory,在实例化一个reader以及scanner,实例化reader会添加5个beanpostProcessor以及一个beanFactoryPostProcessor。接下来会注册beanDefinition到beanFactory当中。Refresh()方法完成spring容器的准备,bean的实例化。初始化一个applicationcontextAware后置处理器,调用后置处理器,以及实例化bean。

  • 属性注入和构造器注入哪一种会有循环依赖的问题?

构造器注入会有循环依赖的问题。属性注入就是setter注入,由于构造函数立刻就会建立对象,没法完成依赖注入。属性注入,能够利用到缓存。一级缓存、二级缓存、三级缓存。

Spring如何实例化对象的?

经过反射,首先经过工厂方法来实例化对象,在经过构造函数,依据参数的类型去实例化,最后经过默认的构造函数,spring底层作了一个这样的判断。

redis

redis工做模型、redis持久化、redis过时淘汰机制、redis分布式集群的常见形式、分布式锁、缓存击穿、缓存雪崩、缓存一致性问题

@PostConstruct:缓存预热,在构造函数初始化以后执行

@PreDestroy:在bean销毁以后执行

常见问题

  • redis性能为何高?

基于内存数据库,数据结构简单,没有磁盘io,主要是io模型牛逼。

  • 单线程的redis如何利用多核cpu机器?
  • redis的缓存淘汰策略?

Redis的config配置文件中配置最大内存,超过以后,会有6种拒绝策略。

1:noeviction: 不删除策略, 达到最大内存限制时, 若是须要更多内存, 直接返回错误信息。 大多数写命令都会致使占用更多的内存(有极少数会例外, 如 DEL )。

2:allkeys-lru: 全部key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。

3:volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。

4:allkeys-random: 全部key通用; 随机删除一部分 key。

5:volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。

6:volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。

  • redis如何持久化数据?

RDB:将持久化的数据写到文件中。

AOF:记录执行的指令。

  • redis有哪几种数据结构?

List 、set、 string、 hash、 sortedSet

  • redis集群有哪几种形式?

哨兵模式:sentinel,监控master slave,若是master挂了,把slave升级为slave。

  • 有海量key和value都比较小的数据,在redis中如何存储才更省内存?
  • 如何保证redis和DB中的数据一致性?

查询若是缓存没有就查库,更新数据库,是缓存失效。

  • 如何解决缓存穿透和缓存雪崩?
  • 如何用redis实现分布式锁?

加锁:

解锁:

相关文章
相关标签/搜索