新鲜出炉的京东面试题

京东面试

1、redis的数据结构分别有什么,各数据结构的底层原理如何实现(zset与set的区别,zset的底层实现。zset如何实现分页功能?(例子:ZRANGEBYSCORE zset01(key) 60 90 limit 2 2))

    string:字符串

    在redis中,其自己定义了一种字符串格式,叫做SDS(Simple Dynamic String),即简单动态字符串

list:列表

ziplist并不是一个类名,其结构是下面这样的:

ziplist类似一个封装的数组,通过zltail可以方便地进行追加和删除尾部数据、使用entries可以方便地计算长度,,但是其依然有数组的缺点,就是当插入和删除数据时会频繁地引起数据移动,

quicklistquicklist是一个双向链表的结构,但是内部又涉及了ziplist,我们可以这么说,在宏观上,quicklist是一个双向链表,在微观上,每一个quicklist的节点都是一个ziplist

在redis.conf中,可以使用下面两个参数来进行优化:

  • list-max-ziplist-size:表示每个quicklistNode的字节大小。默认为2,表示8KB
  • list-compress-depth:表示quicklistNode节点是否要压缩。默认为0,表示不压缩

这种存储方式的优点和链表的优点一致,就是插入和删除的效率很高,而链表查询的效率又由ziplist来进行弥补,所以quicklist就成为了list数据结构的首选

hash:散列表

zipmap
其中相邻的两个字符串就分别是键和值, 就是查找的时间复杂度为O(n),所以只能当作一个轻量级的hashmap来使用

Dict:

如果我们不想更深入的话了解到这种程度就可以了,其中真正存储数据的是dictEntry结构,很明显是一个链表,我们知道这是采用链式结构存储就足够了

这种方式会消耗较多的内存,所以一般数据较少时会采用轻量级的zipmap

 

set:无序集合

intset有一个数据升级的概念,比方说我们有一个16位整数的set,这时候插入了一个32位整数,所以就导致整个集合都升级为32位整数,但是反过来却不行,这也就是柔性数组的由来

如果集合过大,会采用dict的方式来进行存储

zset:有序集合

sorted set,是一个键值对的结构,其键被称为member,也就是集合元素(zset依然是set,所以member不能相同),其对应的值被称为score,是一个浮点数,可以理解为优先级,用于排列zset的顺序

其也有两种存储方式,一种是ziplist/zipmap的格式,这种方式我们就不过多介绍了,只需要了解这种格式将数据按照score的顺序排列即可

另一种存储格式是采用了skiplist,意为跳跃表,可以看成平衡树映射的数组,其查找的时间复杂度和平衡树基本没有差别,但是实现更为简单,形如下面这样的结构(图来源跳跃表的原理):

 

2、redis集群原理是什么?

其实就是分库分表,去中心化

1、集群是如何判断是否有某个节点挂掉

 

  首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。

 

 

 

2、集群进入fail状态的必要条件

 

A、某个主节点和所有从节点全部挂掉,我们集群就进入faill状态。

 

B、如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态.

 

 C、如果集群任意master挂掉,且当前master没有slave.集群进入fail状态

 

 

 

3.redis集群去中心化(所有Master节点并发处理读写)

 

集群中原则每个Master节点都有一个或多个Slave节点。集群中所有的Master节点都可以进行读写数据,不分主次,记redis集群式去中心化的。每个Master节点与Slave节点间通过Goossip协议内部通信,异步复制。不用我们瞎操心(所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.),但是异步赋值会导致某些特定情况下的数据丢失,即,redis集群不能保证数据的强一致性

 

 

 

4.redis集群的分区规则:虚拟槽分区(槽:slot)

 

RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]&16383)映射到0-16383槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据

 

   哈希函数: Hash()=CRC16[key]&16383 按位与

 

redis用虚拟槽分区原因:解耦数据与节点关系,节点自身维护槽映射关系,分布式存储

 

 

5. redisCluster的缺陷(虚拟槽分区的缺点)

 

a,键的批量操作支持有限,比如mset, mget,如果多个键映射在不同的槽,就不支持了

 

b,键事务支持有限,当多个key分布在不同节点时无法使用事务,同一节点是支持事务

 

c,键是数据分区的最小粒度,不能将一个很大的键值对映射到不同的节点

 

d,不支持多数据库,只有0,select 0

 

e,复制结构只支持单层结构,不支持树型结构。  

 

 

 

6.客户端与redis集群交互方式

 

由于Cluster架构中无Proxy层,客户端是直接与集群中的任意可用节点直接交互的,【话是这么说,但是一个请求是怎么找到集群中的一个节点的呢,redis有多种策略,一般使用CRC16去hash(key)计算改请求要分配到具体的哪一个节点上。然后才是  客户端与节点的直接操作】对象保存到Redis之前先经过CRC16哈希到一个指定的Node上,

3、redis主从切换的投票机制原理。

 

4、redis一般Qps是多少?

5、redis过期时间如何设置为毫秒?(PEXPIRE命令 后面单位为毫秒 key milliseconds)

6、mysql tinyint(1)代表什么含义?

7、mysql tinyint取值范围是多少?

8、JVM为什么要调Xss,有什么作用,默认值是多少(1024k),(一般往小调),调整这个参数有什么作用?

9、JVM MetaSpace默认值是多少?

10、ConcurrentHashMap的底层原理。(CAS+Sychronized)

11、创建一个hashMap长度为1000,那么初始的长度应该设置为多少?(比如说,我们有1000个元素new HashMap(1000), 但是理论上来讲new HashMap(1024)更合适,不过上面已经说过,即使是1000,hashmap也自动会将其设置为1024。 但是new HashMap(1024)还不是更合适的,因为0.751000 < 1000, 也就是说为了让0.75 size > 1000, 我们必须这样new HashMap(2048)才最合适,既考虑了&的问题,也避免了resize的问题。)

12、Xms、Xmx为什么要调成一致?你一般设置成多少?

 

13、JDK 1.8默认的GC是什么?

14、GC日志看过吗?里面都有什么?

15、young区一般设置多少次GC后在进入old区?

16、cms、串行GC、并行GC、G1有什么区别?什么时候用cms?什么时候用G1?生产环境如何选择垃圾收集器?

17、mysql如何避免死锁?代码中如何写可以避免死锁?

18、mysql索引如何会失效?

19、什么时候要创建索引?什么时候不应该创建索引?

20、mysql你是如何优化的?

21、mysql优化主要看哪些参数?(explain)

22、Integer、Float值的比较可以用“==”吗?

不要用==,尽量使用equals方法。

23、索引除了BTREE外是否还用过其他索引?

索引是帮助mysql获取数据的数据结构。最常见的索引是Btree索引和Hash索引。

 

不同的引擎对于索引有不同的支持:Innodb和MyISAM默认的索引是Btree索引;而Mermory默认的索引是Hash索引。

 

我们在mysql中常用两种索引算法BTree和Hash,两种算法检索方式不一样,对查询的作用也不一样。

一、BTree

BTree索引是最常用的mysql数据库索引算法,因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量,例如:

select * from user where name like ‘jack%’;

select * from user where name like ‘jac%k%’;

如果一通配符开头,或者没有使用常量,则不会使用索引,例如:

select * from user where name like ‘%jack’;

select * from user where name like simply_name;

二、Hash

Hash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。

但为什么我们使用BTree比使用Hash多呢?主要Hash本身由于其特殊性,也带来了很多限制和弊端:

 

    Hash索引仅仅能满足“=”,“IN”,“<=>”查询,不能使用范围查询。

    联合索引中,Hash索引不能利用部分索引键查询。

    对于联合索引中的多个列,Hash是要么全部使用,要么全部不使用,并不支持BTree支持的联合索引的最优前缀,也就是联合索引的前面一个或几个索引键进行查询时,Hash索引无法被利用。

    Hash索引无法避免数据的排序操作

    由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。

    Hash索引任何时候都不能避免表扫描

    Hash索引是将索引键通过Hash运算之后,将Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行比较,并得到相应的结果。

    Hash索引遇到大量Hash值相等的情况后性能并不一定会比BTree高

    对于选择性比较低的索引键,如果创建Hash索引,那么将会存在大量记录指针信息存于同一个Hash值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据访问,而造成整体性能底下。

 

1. hash索引查找数据基本上能一次定位数据,当然有大量碰撞的话性能也会下降。而btree索引就得在节点上挨着查找了,很明显在数据精确查找方面hash索引的效率是要高于btree的;

2. 那么不精确查找呢,也很明显,因为hash算法是基于等值计算的,所以对于“like”等范围查找hash索引无效,不支持;

3. 对于btree支持的联合索引的最优前缀,hash也是无法支持的,联合索引中的字段要么全用要么全不用。提起最优前缀居然都泛起迷糊了,看来有时候放空得太厉害;

4. hash不支持索引排序,索引值和计算出来的hash值大小并不一定一致。

24、创建对象都有哪些方式?

1,new

 

Student s = new Student();

 

在堆储存区开辟了一块空间,其对象的引用存储在栈存储区上。

 

 

反射 reflect

 

java的反射机制是指,

 

获得类的Class 对象的3中方法:

 

1,类名.class (任意数据类型,都会有一个class 属性)

 

2,Class.forName("java.lang.String"); 类的全路径

 

3,类的实例化对象下,有getClass() 方法。

 

3,clone

 

调用clone,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。

 

前提,必须要实现Cloneable 接口,本地实现 protected native Object clone() throws CloneNotSupportedException;

 

Demo clone = (Demo) newInstance.clone();

 

4,反序列化

 

序列化:将堆内存中的java 对象通过某种方式,存储到磁盘上或者传输给其他网络节点,也就是java对象转成二进制。

 

反序列化:与序列化相反,再将序列化之后的二进制串再转成数据结构或对象。

 

 

25、线程都用了哪些设计模式?

多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future、Master-Worker、Guard Susperionsion、不变、生产者-消费者 模式;jdk除了定义了若干并发的数据结构,也内置了多线程框架和各种线程池;    锁(分为内部锁、重入锁、读写锁)、ThreadLocal、信号量等在并发控制中发挥着巨大的作用。

 

多线程设计模式:

1.Single Threaded Execution Pattern

   [同一时刻只允许一个线程操作]

 

比喻:三个挑水的和尚,只能同一时间一个人过桥,不然都掉河里喂鱼了。

总结:在多个线程同时要访问的方法上加上synchronized关键字。

 

 

 

 

2.Immutable Pattern

   [变量赋值一次后只能读取,不能改变。]

   比喻:一夫多妻制,多个妻子共享一个丈夫。一旦赋值,任何一个妻子不能更改共享的 husband为其它人。

   总结:将多线程共享的变量用final关键字修饰。

 

 

3.Guarded Suspension Pattern

   [要等到我准备好哦,没准备好就在门口等着,准备好了再叫你。]

   比喻:

 

        GG:小伙子去MM家,敲门...

        MM:我在换衣服,稍等。

        GG:等待 【调用wait()方法挂起自己的线程】

        MM:换好了,进来吧 【调用notify()或着notifyAll()方法通知GG】

   总结:判断某个条件是否为真,如果条件成立则继续执行一步,如果条件不成立用wait()方法挂起当前线程,条件为真后由另一个线程用notify()或 着notifyAll()方法唤醒挂起的线程。

 

 

4.Balking Pattern

   [有人在做了?哈哈,太好了,我就不过去了!]

   比喻:饭店里我想好了要点的菜后,高高的举起手示意服务生过来,一个服务生准备过去的时候看到另外一个服务生已经过去了,哈哈已经有人过去了我就不过去了。

   总结:设置一个volatile的共享变量,多个线程进入同一方法时,判断变量的值是否为真,如果为真说明有人已经在做这个工作了,线程返回,反之将变量赋值为真并执行。

   

5.Producer-Consumer Pattern

   [生产-消费者,你生产蛋榚我来吃。]

   比喻(1):一群猪围着猪食槽的一头,塞进几块玉米饼后,群猪争先恐后从食槽头抢,谁抢到谁吃。

   比喻(2):一群猪围着猪食槽的头和尾,塞进几块玉米饼后,群猪争先恐后从食槽头和食槽尾抢,谁抢到谁吃。

   总结:<1>生产者将生产出来的东西add(E e)到一个Queue,然后唤醒正在从Queue等东西的线程,用poll()方法从队列的头获取到东西,当Queue里的东西被取完,取东西的线程再次被挂起。

           <2>生产者将生产出来的东西放入(方法很多,有add(E e)、addFirst(E e)、addLast(E e)等)一个Deque,然后唤醒正在从Queue等东西的线程,线程从Deque的头和尾取东西,当Deque里的东西被取完,取东西的线程再次被挂起。

 

 

6.Read-Write Lock Pattern

   [学生抄的时候,不允许老师擦掉黑板上的字。]

   比喻:老师在黑板上写了些字,下面的同学在拼命的抄,过会儿老师要写些新的字,写新字要擦掉原来的那些,问:都写完了么?如果都回答写完了,就擦掉原来的字写新的,如果还有一个回答没写完,就等待最后一个同学抄完再写。

   总结:Jdk1.5及以上有专门的读写锁实现

        java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

       java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

7.Thread-Per-Message Pattern  

   [一任务一线程]

   总结:一个客人一个妞服务,好是好,可是天朝扫黄太厉害,现在狼多肉少哇,用线程池吧,轮流服务。

 

 

8.Worker Thread Pattern

   [同Producer-Consumer Pattern]

 

 

 

 

9.Future Pattern

   [给您一张提货单,下午来取。]

   比喻:

       李刚:大钞票一摔,来只大蛋榚!

       店员:对不起没这么大的,但现做,给您张单子,下午xx点来取。

       李刚:取货单??,上面都写了些啥?

            订单号:SB01

             客户名:李刚

             已付款:250

          取货时间:PM2:50   

   总结:调用某个方法时,这个方法可能需要请求其它系统,这个过程比较耗时,为了提高客户的体验需要方法立即返回,过一段时间再查询结果。

          在程序里声明一个Hashmap,Key保存订单号,Value保存生产出的蛋榚,然后根据订单号取得对应的蛋榚。

 

 

10.Two-Phase Termination Pattern

   [玩具收拾好,睡觉去]

   比喻:小孩子在玩具,到点了妈妈喊:别玩了,睡觉去!

   总结:一个线程在while(!isInterrupted()){..}循环中执行,另外一个线程判断某个条件达到后获得准备被结束线程的句柄,调用interrupt()

        设置线程的中断状态。

11.Thread-Specific Storage Pattern

   [线程私有物品保管箱]

    总结:一个方法可能会被同一个线程访问多次,如果每访问一次就要声明一个数据库连接的Connection变量,则对程序的性能有影响。将Connection放在ThreadLocal里,这样每次访问就不必再产生一个Connection,同一个线程对应同一个Connection.

 

26、线程池原理?一般是如何设置核心线程数与最大线程数的?是否可以用Excutors创建?为什么?

27、快排的写法?

28、如何排查CPU高的进程?快速定位问题?

29、哪些操作会导致CPU占用高?

30、CAS全称是什么,原理是什么?他有什么作用,会导致什么问题,如何解决导致的问题?除了ABA还有什么问题?

31、voletile 关键字是做什么的?有什么特性?为什么禁止指令重排?

作用:

内存一致性

ThreadA再修改标志位flag的时候从主内存中刷新变量的最新值,同时将线程B工作内存中的flag变量置为不可靠状态(dirty),那么下次ThreadB如果要使用flag标志位的时候就会从主内存中读取变量的最新值,从而保证了变量再不同线程中的一致性.

 

防止指令重排

 

内存屏障
volatile关键字可以实现变量在各线程中的一致性,并且具有禁止指令重排的功能。其实这两个特性是通过内存屏障来实现的.

内存屏障是jvm上的指令,jvm上还有其它指令例如

(1) lock:将主内存中的变量锁定,为一个线程所独占

 

(2) unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量

 

(3) read:将主内存中的变量值读到工作内存当中

 

(4) load:将read读取的值保存到工作内存中的变量副本中。

 

(5) use:将值传递给线程的代码执行引擎

 

(6) assign:将执行引擎处理返回的值重新赋值给变量副本

 

(7) store:将变量副本的值存储到主内存中。

 

(8) write:将store存储的值写入到主内存的共享变量当中。

 

32、springMVC解释一下@Autowire注解底层是如何工作的?

33、threadLocal类有什么作用?

 

34、tomcat默认最大的线程数是多少?

maxThreads(最大线程数):每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务可以同时处理多少个请求,默认200.

35、mysql默认最大连接数是多少?

  accepCount(最大等待数):当调用Web服务的HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100.如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)。

maxConnections(最大连接数):这个参数是指在同一时间,tomcat能够接受的最大连接数。一般这个值要大于maxThreads+acceptCount。

 

36、我们在写输入的日志代码时有时候会写log.isinfoEnable(),不写这句与写这句判断有什么区别?

log4j中log.isDebugEnabled(), log.isInfoEnabled()和log.isTraceEnabled()作用

Debug,Info和Trace一般会打印比较详细的信息,而且打印的次数较多,如果我们不加log.isDebugEnabled()等
进行预先判断,当系统loglevel设置高于Debug或Info或Trace时,虽然系统不会答应出这些级别的日志,但是每次还是会拼接
参数字符串,影响系统的性能。

 

这3个方法是对对项目的优化方法,加这个方法目的地在于如果代码中存在连接字符串的情况,打印信息时会出现太多的拼接字符串影响系统性能。如果系统中是固定字符串加不加都可以。

 

 

关注下方公众号获取更多优质文章>>>

新鲜出炉的京东面试题_第1张图片

你可能感兴趣的:(面试)