真有两把刷子+藜麦科技

上午:真有两把刷子
  • 自我介绍

  • Nginx负载均衡是怎么实现的?
    将服务器收到的请求按照一定的分发规则分发到不同的服务器上的过程,称为负载均衡。

  • 配置IPHash与轮询有什么区别?
    iphash是根据请求者ip的hash值将请求发送到后台服务器中,可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。
    weight是根据权重来分发请求到不同的机器中,指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

  • 负载出现session共享的问题怎么解决?
    使用session服务器(将应用服务器状态分离,分为无状态的应用服务器和有状态的session服务器,然后针对这两种服务器的不同特性分别做设计架构) 。基于cache DB缓存的Session共享(推荐,Spring-Session也是同样的原理,同自定义的JRedis一起配置可以实现目的):使用Redis存取Session信息,应用服务器发生故障时,当Session不在内存中时就会去CacheDB中查找(要求Redis支持持久化),找到则复制到本机,实现Session共享和高可用。

  • HashMap底层是怎么实现的?JDK7&JDK8? 1.8默认是红黑树吗? 如果在哈希冲突的时候直接就在链表中增加吗? hash扩容的机制?中间做了些什么?
    Java8之前使用数组+链表 Java8及之后 当链表长度小于8时,使用数组+链表,当大于这个阈值之后,就会转化成数组+红黑树


    通过分析源码我们知道了HashMap通过resize()方法进行扩容或者初始化的操作。Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。

void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    //判断是否有超出扩容的最大值,如果达到最大值则不进行扩容操作
    if (oldCapacity == MAXIMUM_CAPACITY) {
      threshold = Integer.MAX_VALUE;
      return;
    }
 
    Entry[] newTable = new Entry[newCapacity];
    // !!!transfer()方法把原数组中的值放到新数组中!!!
    transfer(newTable, initHashSeedAsNeeded(newCapacity));
    //设置hashmap扩容后为新的数组引用
    table = newTable;
    //设置hashmap扩容新的阈值
    threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
  }
void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    for (Entry e : table) {
      while(null != e) {
        Entry next = e.next;
        if (rehash) {
          e.hash = null == e.key ? 0 : hash(e.key);
        }
        //!!!通过key值的hash值和新数组的大小算出在当前数组中的存放位置!!!
        int i = indexFor(e.hash, newCapacity);
        e.next = newTable[i];
        newTable[i] = e;
        e = next;
      }
    }
  }
static int indexFor(int h, int length) {  //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的
     return h & (length-1);  
}
  • 为什么数组长度要保证为2的幂次方?
    只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,即实现了key的定位,2的幂次方也可以减少冲突次数,提高HashMap的查询效率;
    如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;如果 length 不是 2 的次幂,比如 length 为 15,则 length - 1 为 14,对应的二进制为 1110,在于 h 与操作,最后一位都为 0 ,而 0001,0011,0101,1001,1011,0111,1101 这几个位置永远都不能存放元素了,空间浪费相当大,更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。
    一招破解 Java 集合类面试题
    Java 8系列之重新认识HashMap
    40个Java集合类面试题和答案(转载)
  • 数组跟链表的区别?
    数组在内存中是连续的,链表是分散的
    读取效率对比
    插入删除效率对比

  • 如果实现内存缓存是该怎么实现,不用redis
    微服务该如何设计缓存?

  • 简单说下synchronized?
    synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字保证被它修饰的方法或者代码块在任意时刻有一个线程执行。
    修饰静态方法:给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管new了多少个对象,只有一份)。所以如果线程A调用一个实例对象的非静态synchronized方法,另一个线程B调用该实例对象所属类的静态synchronized方法,那么不会发生互斥,因为访问静态synchronized方法占用的锁是当前类的锁,而访问非静态synchronized方法是占用的锁是当前实例对象的锁。
    修饰实例方法:作用于当前对象实例加锁,进入同步代码块之前要获得当前对象实例的锁。
    修饰代码块:制定加锁对象,对给定对象加锁,进入同步代码块前要获得给定对象的锁。
    总结:synchronize关键字加到静态方法和synchronize(class)代码块都是给类加锁,synchronized关键字修饰实例方法是给对象实例加锁,

  • java中锁的三个特性? 理解三个特性(并发三特性)
    原子性 定义:一个或多个操作作为一个整体,要么都执行,要么都不执行,并且操作在执行的过程中不会被线程调度机制打断;而且这种操作一旦开始,就会一直执行到结束,中间不会有任何上下文切换。
    Java内存模型只实现了基本的原子性,像i++这种操作,必须使用synchronized或者lock来保证整个代码的原子性。线程在释放锁之前,必定把i值刷会主存。

有序性 定义:程序按照代码的先后顺序执行。
一般来说处理器为了提高执行效率,可能会对输入的代码进行优化,不能保证执行顺序和代码顺序完全一致,但是保证程序的执行结果与按顺序执行的结果是相同的。
但是在多线程下,如果指令重排,可能不会像单线程那样安全。


可见性 定义:多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立刻看到修改的值。

  • 工厂模式与策略模式的区别?

  • Spring的bean是单例的吗?
    Spring中的bean默认是单例的,除了单例,还有prototype,request等等。

  • Spring中的bean单例有什么优点
    单例的bean只有在第一次才会创建新的bean,之后都会在缓存中拿,不会频繁创建对象。所以会有性能上的优势。

    1. 减少新生成实例的消耗,新生成实例消耗主要分为两方面。第一:Spring会通过反射或者cglib来生成bean实例,这都是性能消耗。第二:给对象分配内存会涉及到复杂算法。
    2. 减少JVM垃圾回收,由于不会每个请求都生成新的bean,所以回收的也少了
    3. 可以快速获得bean,因为第一次是生成的,后面都是复用的。
  • NIO与BIO的区别?
    首先说明NIO是非阻塞同步的,BIO是阻塞同步的。
    然后从NIO三个特性给NIO带来的一些改进来分析。
    阻塞:发起一个请求,调用者一直等待请求结果返回,也就是当前进程会挂起,无法从事其他任务,只有当条件就绪时才能继续。
    非阻塞:发起一个请求,调用者不许等待结果返回,可以先去干其他的事情。
    NIO的三个特性

    • Channel(通道)
    • Buffer(缓冲区)
    • Selector(选择器)

    Channel:NIO 通过Channel(通道) 进行读写。
    通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。

    IO NIO
    面向流 面向缓冲
    阻塞IO 非阻塞IO
    选择器

    面向流与面向缓冲
    NIO的优势来源于它的缓冲机制,不管是读还是写都以块的形式写到缓冲区里,NIO实际让我们对IO的操作更加操作系统的实际过程。
    面向流意味着每次都流中读一个或多个字节,直至读取所有字节,他们没有被缓存在任何地方,此外,他不能前后移动流中的数据。如果需要移动从流中读取的数据,需要先将它缓存在一个缓冲区。
    阻塞与非阻塞
    BIO的各种流是阻塞的,这意味着当一个线程调用read()方法或者write()方法时,该线程被阻塞,直到一些数据被读取,或数据完全写入,此线程在此期间不能干任何其他的事情,
    NIO的非阻塞模式会在线程收到读取请求之后,如果目前没有数据可用,就什么都不会获取,直至数据变得可以被读取之前,该线程可以做任何的事情,非阻塞写也是,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程可以同时去做别的事情,线程通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作,所以一个线程可以管理一个或多个输入输出通道(channel)
    选择器
    可以用于使用单个线程处理多个通道,因此只需要较少的线程来处理这些通道。
    Netty 的出现很大程度上改善了 JDK 原生 NIO 所存在的一些让人难以忍受的问题。
    Java NIO系列教程(十二) Java NIO与IO
    还不了解 Netty 是什么? u need try this one

  • 如果用NIO框架,不破坏它的特性,要保证哪些点?

  • 觉得工作当中的优势是什么?

  • 期望的公司是什么样的?

  • 为什么要想使用比较新的框架

  • SpringMVC与boot的区别?boot是怎么做的?
    Spring最初利用依赖注入(DI)和面向切面(AOP)来解耦应用组件,大家觉得比较好用,就按照这个模式搞了一个MVC框架(一些用Spring解耦的组件)出来,用来开发web应用,然后就发现每次会写一些样板代码,为了简化工作流程,于是开发出一个懒人整合包(starter)这套就是SpringBoot
    SpringBoot实现了自动配置,降低了项目搭建的复杂度。
    spring boot与spring mvc的区别是什么?

下午:藜麦
  • 自我介绍

  • 看用了Nginx做反向代理,那么项目架构是怎样做的?可能面试官认为Nginx可能会涉及到分布式部署?

  • 怎么理解加深了算法效率重要性的理解?

  • 设计模式大概了解哪些?过滤器是什么思想(责任链模式)?
    责任链模式:
    责任链模式为请求创建了一个接收者对象链,每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么他会把请求传递给下一个接收者,以此类推
    责任链模式避免了请求的发送者和接受者耦合在一起,让多个对象都有可能接收请求,讲这些对象连成一条链,并且沿着这条链传递请求,直到有对象处理他为止。

  • 通信中TCP与UDP有什么区别?还有哪些协议?
    TCP与UDP输入传输层协议


    TCP是面向连接的可靠的传输形式为字节流的协议,UDP是无连接的不可靠的传输形式为数据保温段的协议。

    UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 确是一种最有效的工作方式(一般用于即时通信),比如: QQ 语音、 QQ 视频 、直播等等
    TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。 TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务(TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源),这一难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。TCP 一般用于文件传输、发送和接收邮件、远程登录等场景。

  • TCP与HTTP有什么区别?
    TCP属于传输层协议,http属于应用层协议,http是基于TCP连接基础上的,简单的说,TCP就是单纯的建立连接,不涉及任何我们需要请求的数据,简单的传输,http是用来收发数据,即实际应用上来的。

  • 为什么NIO是非阻塞的,怎么体现?
    NIO的非阻塞模式会在线程收到读取请求之后,如果目前没有数据可用,就什么都不会获取,直至数据变得可以被读取之前,该线程可以做任何的事情,非阻塞写也是,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程可以同时去做别的事情,线程通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作,所以一个线程可以管理一个或多个输入输出通道(channel)

  • dubbo有没有了解过?

  • redis有哪些数据类型?
    redis支持五中数据类型
    string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)

  • 一般从哪些方面进行SQL优化?
    腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列

  • 联合索引用过吗?聚集索引和非聚集索引?
    联合索引(复合索引):两个或两个以上列的索引被称为复合索引
    通俗理解:利用索引中的附加列,可以缩小搜索的范围,但也有局限性,复合索引的结构和电话簿类似,如果只知道姓,那么电话簿很有用,如果知道名和姓,电话簿更有用;但如果只知道名字,电话簿将没有用处。
    所以说在创建联合索引的时候,应该仔细考虑索引的顺序,对索引中的所有列执行搜索或仅对前几列进行搜索,复合索引非常有用,如果仅对后几列进行搜索,复合索引没有用。
    注意:多个单列索引在多条件查询时只会生效第一个索引,所以多条件联合查询时最好使用联合索引。
    最左前缀原则:
    顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上,
    注:如果第一个字段是范围查询需要单独建一个索引
    注:在创建联合索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。这样的话扩展性较好,比如 userid 经常需要作为查询条件,而 mobile 不常常用,则需要把 userid 放在联合索引的第一位置,即最左边
    联合索引的本质:
    当创建(a,b,c)联合索引时,相当于创建了(a)单列索引,(a,b)联合索引以及(a,b,c)联合索引
    想要索引生效的话,只能使用 a和a,b和a,b,c三种组合;当然,我们上面测试过,a,c组合也可以,但实际上只用到了a的索引,c并没有用到!
    注:这个可以结合上边的 通俗理解 来思考!
    其他知识点:
    1、需要加索引的字段,要在where条件中
    2、数据量少的字段不需要加索引;因为建索引有一定开销,如果数据量小则没必要建索引(速度反而慢)
    3、如果where条件中是OR关系,加索引不起作用
    4、联合索引比对每个列分别建索引更有优势,因为索引建立得越多就越占磁盘空间,在更新数据的时候速度会更慢。另外建立多列索引时,顺序也是需要注意的,应该将严格的索引放在前面,这样筛选的力度会更大,效率更高。
    多个单列索引和联合索引的区别详解

  • Spring的IOC是怎么理解的? 实现原理是用什么集合存储bean类的?
    IoC(Inverse of Control)控制反转是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC在其他语言中也有应用,并非Spring特有,IOC容器是Spring用来实现IOC的载体,IOC容器实际就是一个Map,Map中存放的是各种对象。使用IOC的好处:第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。

  • 知道有哪些集合?

  • ConcurrentArrayList与ArrayList有什么区别?ConcurrentArrayList的实现原理是什么?

  • ConcurrentHashMap1.8之后的加锁机制?
    JDK1.7之前:ConcurrentHashMap 使用segment分段锁机制
    将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问。
    ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。


    JDK1.8: 取消了segment分段锁,使用CAS和synchronized来保证线程安全,数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。Java 8在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(long(N)))
    synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。

  • volitate关键字的使用?
    volatile关键字只能用来修饰变量,主要作用有两个
    1.保证不同线程对该变量操作的内存可见性
    2.禁止指令重排序
    如果一个变量被声明为是volatile的,那么当我读变量时,总是能读到他的最新值,这里的最新值是指不管其他哪个线程对该变量做了写操作,都会立刻被更新到主存之中,我也能从主存之中读到这个被刚写入的值,也就是说volatile关键字可以保证可见性以及有序性。
    但是不能保证原子性,要想保证原子性,必须使用synchronized、lock或者并发包下的atomic的原子操作类了。即面对基本数据类型的自增,自减,加法操作,减法操作进行封装,以保证这些操作是原子操作。
    在哪里使用过volatile关键字



    Java面试官最爱的volatile关键字

  • JVM的内存模型?JVM数据区?内存空间?

  • 与外部系统用的WebService Restful规范的接口怎么理解?接口用的什么协议?还知道什么RPC框架?

  • 请说明什么是 RESTful ?到底 REST 和 SOAP、RPC 有何区别?
    restful是一种基于http架构的风格,而不是具体的协议。
    RPC是远程方法调用,服务器端和客户端可以是异构的系统,可跨平台。RPC框架包括dubbo等
    SOAP是通过XML传输消息来调用web服务的一种协议,指的是webservice协议,使用XML作为通信数据,比rest重量。
    rest是一种基于http的RPC
    rest使用json来传递数据,使用url来区分操作对象,使用PUT/DELETE/GET/POST HTTP方法来对应CURD操作。GET 获取信息,PUT修改,POST新增,DELETE删除

  • 用什么去发布restful规范的接口?

  • final关键字与static关键字?

  • Linux 文件中的正则查找命令是什么? tail命令是什么意思? cat命令是什么意思?

  • 如何防止sql注入?

    • 使用预编译语句PreparedStatement
      原理:
      sql注入只对sql语句的准备(编译)过程有破坏作用
      而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
      而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.

        
    • 使用正则表达式过滤传入的参数
    • 检查变量数据类型和格式

    防止SQL注入的五种方法

  • 加了static的变量在内存中存放在哪里,不加static的呢?

  • 说一下死锁?

    • 什么是死锁?
      死锁是指多个进程因相互竞争资源(相互等待)而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。
    • 死锁的四个必要条件?
      互斥条件:一个资源每次只能被一个进程使用,即在一段时间内,某资源只能被一个线程占用,其他线程如果想请求,只能等待。
      请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
      不可剥夺条件:进程所获得的资源不能被其他进程强行夺走,只能主动释放。
      循环等待条件:许多进程形成了首尾相接循环等待资源的关系。
    • 死锁预防
      通过破坏死锁四个必要条件来预防死锁。由于资源互斥是资源使用的固有特性,所以互斥性无法破坏。
      1. 破坏“不可剥夺”条件: 一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将被隐式的释放重新加入到 系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的资源以及新申请的资源才可以重新启动,执行。
      2. 破坏”请求与保持条件“:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。
      3. 破坏“循环等待”条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的,稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的进程才能申请较大编号的进程。

你可能感兴趣的:(真有两把刷子+藜麦科技)