京东面经:乐观锁是怎么实现,线程池线程的提交方式和优缺点

1.对称加密和非对称加密的优缺点,为什么这么做?RSA

2.线程池线程的提交方式和优缺点。

3.Protobuff和msgpack的优缺点还有坑在哪里?

4.对JVM的了解和观测,什么时候进行full gc?

5.MySQL的索引有什么用?都有哪些种索引?

6.Rpc框架设置超时时间的意义是什么?

7.有没有对程序进行优化过,和对数据库进行优化过?

8.平时是怎么学习的,理论有没有实践过。

9.接收mq时如果数据库出现了错误是怎么做的?

10.MySQL有哪些索引?为啥用B+树,其他结构不行么?

11.乐观锁是怎么实现的?

12.平时MySQL指定过加锁方式么?用过乐观锁悲观锁么?

13.Guava缓存除了做缓存还能做什么?和Redis的优缺点。

1.对称加密和非对称加密的优缺点,为什么这么做?RSA浅谈;

(1) 对称加密:双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。

优点:速度快,对称性加密通常在消息发送方需要加密大量数据时使用,算法公开、计算量小、加密速度快、加密效率高。 缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后 使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘 钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。

在对称加密算法中常用的算法有:DES、AES等。 AES:密钥的长度可以为128、192和256位,也就是16个字节、24个字节和32个字节 DES:密钥的长度64位,8个字节。

非对称加密:一对密钥由公钥和私钥组成(可以使用很多对密钥)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。私钥只能由一方保管,不能外泄。公钥可以交给任何请求方。

缺点:速度较慢 优点:安全

在非对称加密算法中常用的算法有: RSA等

(2)RSA浅将

RSA加密/解密

使用公钥加密的数据,利用私钥进行解密 使用私钥加密的数据,利用公钥进行解密 没错,RSA加密使用了"一对"密钥.分别是公钥和私钥,这个公钥和私钥其实就是一组数字!其二进制位长度可以是1024位或者2048位.长度越长其加密强度越大,目前为止公之于众的能破解的最大长度为768位密钥,只要高于768位,相对就比较安全.所以目前为止,这种加密算法一直被广泛使用.

RSA的弊端 由于RSA算法的原理都是大数计算,使得RSA最快的情况也比对称加密算法慢上好几倍。速度一直是RSA的缺陷,一般来说RSA只用于小数据的加密.RSA的速度是对应同样安全级别的对称加密算法的1/1000左右。

RSA终端命令演示 由于Mac系统内置OpenSSL(开源加密库),所以我们可以直接在终端上使用命令来玩RSA. OpenSSL中RSA算法常用指令主要有三个,其他指令此处不介绍。

命令 含义 genrsa 生成并输入一个RSA私钥 rsautl 使用RSA密钥进行加密、解密、签名和验证等运算 rsa 处理RSA密钥的格式转换等问题

2.线程池线程的提交方式和优缺点。

(1)提交方式

  1. Single Thread Executor:只有一个线程的线程池,因此所有提交的任务是顺序执行。 代码:Executors.newSingleThreadExecutor()

3.Cached Thread Pool:线程池里有很多线程需要同时执行,老的可用线程将被新的任务触 重新执行,如果线程超过60秒内没执行,那么将被终止并从池中删除。 代码:Executors.newCachedThreadPool()

  1. Fixed Thread Pool:拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待。 代码:Executors.newFixedThreadPool(4) 在构造函数中的参数4是线程池的大小,你可以随意设置,也可以和cpu的核数量保持一致,获取cpu的核数量方式:int cpuNums = Runtime.getRuntime().availableProcessors();

  2. Scheduled Thread Pool:用来调度即将执行的任务的线程池。 代码:Executors.newScheduledThreadPool()

  3. Single Thread Scheduled Pool:只有一个线程,用来调度任务在指定时间执行。 代码:Executors.newSingleThreadScheduledExecutor()

(2)优缺点

1.线程使应用能够更加充分合理的协调利用cpu 、内存、网络、i/o等系统资源。 2.线程的创建需要开辟虚拟机栈,本地方法栈、程序计数器等线程私有的内存空间。 3.在线程的销毁时需要回收这些系统资源。频繁的创建和销毁线程会浪费大量的系统资源,增加并发编程的风险。 4.另外,在服务器负载过大的时候,如何让新的线程等待或者友好的拒绝服务?这些丢失线程自身无法解决的。所以需要通过线程池协调多个线程,并实现类似主次线程隔离、定时执行、周期执行等任务。

线程池的作用包括: 1.利用线程池管理并复用线程、控制最大并发数等。 2.实现任务线程队列缓存策略和拒绝机制。 3.实现某些与时间相关的功能,如定时执行、周期执行等。 4.隔离线程环境。比如,交易服务和搜索服务在同一台服务器上,分别开启两个线程池,交易线程的资源消耗明显要大;因此,通过配置独立的线程池,将较慢的交易服务与搜索服务隔开,避免个服务线程互相影响。

3.Protobuff和msgpack的优缺点还有坑在哪里?

1.msgpack的序列化速度比protobuf要快一些,但反序列化要比protobuf要慢一些,但总体都接近 2.msgpack可以直接序列化类对象,但protobuf需要先写描述映射文件(.proto) 3.msgpack支持的基本类型比protobuf支持的要全面些 4.protobuf的描述文件无法实现类的继承(不知V2.0以上会如何) 5.然而,msgpack在unity下的ios与wp平台下无法支持,但protobuf可以支持全平台

4.对JVM的了解和观测,什么时候进行full gc?

(1)Java语言运行的过程:

Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’(.class文件,也就是0,1二进制程序),然后在OS之上的Java解释器中解释执行。 注:JVM(java虚拟机)包括解释器,不同的JDK虚拟机是相同的,解释器不同。 (个人补充:例如JDK中的编译器javac)将我们的java文件编译成.classjava字节码文件,JVM的解释器解析这些字节码,映射到CPU指令集或者OS的系统调用;eclipse使用的不是javac!eclipse的JDT用的是自己写的编译器,对javac没有任何依赖关系,这一直是Eclipse一件自豪的事情。eclipse和JDK的编译结果可能不一致。 javac的编译方法有:编译时首先读入java源程序(即在MS-DOS命令行下键入javac HelloWorld.java等文件名参数和其他选项参数),然后进行语法检查,如果出现问题就终止编译。语法检查通过后,生成中间代码即字节码,字节码文件名和源文件名相同,扩展名为.class。)

(2)JVM:

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。 java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。

(3)JVM执行程序的过程 :

I.加载.class文件 II.管理并分配内存 III.执行垃圾收集

(4)JRE(java运行时环境)由JVM构造的java程序的运行环境

堆内存划分为 Eden、Survivor 和 Tenured/Old 空间,如下图所示:

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,对老年代GC称为Major GC,而Full GC是对整个堆来说的,在最近几个版本的JDK里默认包括了对永生代即方法区的回收(JDK8中无永生带了),出现Full GC的时候经常伴随至少一次的Minor GC,但非绝对的。Major GC的速度一般会比Minor GC慢10倍以上。下边看看有那种情况触发JVM进行Full GC及应对策略。

  1. System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

2、老年代空间不足 老年代空间只有在新生代对象转入及创建大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误: java.lang.OutOfMemoryError: Java heap space 为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

3、永生区空间不足 JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息: java.lang.OutOfMemoryError: PermGen space 为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

4、CMS GC时出现promotion failed和concurrent mode failure 对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。 具体原因和解决方案可以查看使用CMS垃圾收集器产生的问题和解决方案

5、HandlePromotionFailure

在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间,这是一个较为复杂的触发情况,例如程序第一次触发Minor GC后,有6MB的对象晋升到老年代,那么当下一次Minor GC发生时,首先检查老年代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。

当新生代采用PS GC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB,如小于,则触发对旧生代的回收。

除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过 java -Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

6、堆中分配很大的对象 所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。 为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的

5.MySQL的索引有什么用?都有哪些种索引?

索引是什么,首先我们可以举个例子,字典大家应该都使用过,我们可以使用目录快速定位到所要查找的内容,那么索引跟目录的作用类似,在数据库表记录中,利用索引,可以快速过滤查找到数据记录。

(1)索引类型分类

普通索引:加快查询速度 唯一索引:加快查询速度,并且可以限制列值的唯一性,允许为空 唯一索引包括联合唯一索引,多列形成的唯一索引,这些列可以唯一确定一条表记录,可以为空 全文索引:主要针对文本的内容进行分词,加快查询速度 联合索引:多列组成的索引,查询效率提升高于多个单列索引合并的效率 主键索引:主键唯一性,加快查询速度,不能为空

(2)索引结构分类

索引有很多分类,例如B-tree索引,哈希索引,全文索引等等,索引的实现是在存储引擎层,并不是在后端服务器层,所以不同的存储引擎支持的索引结构也不一定一样

B-tree索引:      B-tree 索引普遍存在于存储引擎中,他使用B-tree数据结构来存储数据,如果对树形数据结构比较了解的话,就知道B-tree索引所带来的好处了,他的每个叶子节点都会包含下一个节点的指针,非常方便查询数据      B-tree 适用于全键值,键值范围,或者前缀查找

哈希索引:      哈希索引基于哈希表实现,对于每一行数据,存储引擎会对所有的索引列计算一个哈希码,然后存储引擎会基于这个哈希码来查找数据,小编感觉有点像HashMap 中槽的查询过程

全文索引:      全文索引在几种索引结构类型中比较特殊,他查找的是文本中关键词

(3)索引的正确使用

索引是建立在系统文件上的,会占用一定的内存空间,另外数据在更新的时候也会去维护索引,消耗内存,所以索引一定要正确的使用,索引并不是越多越好,要根据具体的查询业务来规划索引的建立。

(4)建议不要使用索引的几种情况:

1. 区分度不是很大的字段,例如 性别 sex     2. 频繁更新的字段     3. 字符串类型的字段 或者 文本类型的字段     4. 不在where列中出现的索引

(5)索引失效的几种情况:

1. 查询列中有函数计算      2. 查询列中有模糊查询,"%cloum",可以使用"cloum%" 代替,如果要使用"%column%",那么select 列中是索引列     3. 如果查询条件中有or, 索引会失效,除非所有条件都加上索引     4. 使用不等于(!= 或者 <>)     5. is null 或者 is not null     6. 字符串不加引号,会导致索引失效     7. 最左原则,联合索引中会遵循最左原则,即如果要使用联合索引,那么前面的索引列一定要包含,举个例子,有个联合索引(a,b,c) 那么查询条件中只能是 a=1 或者 a=1 and b=1 或者 a=1 and b=1 and c=1,不然索引就会失效

猜你喜欢

转载自juejin.im/post/5decc48d6fb9a016023e7721