面试题目总结一

马上又到了金九银十是招聘的旺季:博主这里收集了一些相应的面试题目,提供给大家参考学习!!!!!!!!当然这里也仅仅是参考,更多的知识还是自己不断的去积累学习掌握!!!

String、StringBuffer、StringBuilder的区别

  • 1、先介绍三者的相同之处:都可用于存储字符串,但是在存储的过程中又有不同之处:string只能存放不可变的字符串,而stringbuffer与stringbuilder可存放可变的字符串
  • 2、从使用安全方面进行区别:string与stringbuilder是线程非安全的,而stringbuffer是线程安全的(因为在stringbuffer的实现方法中有加锁操作)
  • String,StringBuffer,StringBuilder,都是final类,不允许被继承,在本质上都是字符数组,不同的是,String的长度是不可变的而后两者长度可变,在进行连接操作时,String每次返回一个新的String实例,而StringBuffer和StringBuilder的append方法直接返回this,所以当进行大量的字符串连接操作时,不推荐使用String,因为它会产生大量的中间String对象。
  • StringBuffer和StringBuilder的一个区别是,StringBuffer在append方法前增加了一个synchronized修饰符,以起到同步的作用,为此也降低了执行效率;若要在toString方法中使用循环,使用StringBuilder。
  • 对于三者的总结:1)如果操作少量的数据用String
  •                                     2)单线程下操作大量的数据用StringBuilder
  •                                     3)多线程下操作大量的数据用StringBuffer

看过哪些源码?Object类里有哪些方法?hashcode、equals和==之间的区别“

Object类中的常用方法如下:

  • registerNatives()   //私有方法
  • getClass()    //返回此 Object 的运行类。
  • hashCode()    //用于获取对象的哈希值。
  • equals(Object obj)     //用于确认两个对象是否“相同”。
  • clone()    //创建并返回此对象的一个副本。 
  • toString()   //返回该对象的字符串表示。   
  • notify()    //唤醒在此对象监视器上等待的单个线程。   
  • notifyAll()     //唤醒在此对象监视器上等待的所有线程。   
  • wait(long timeout)    //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或        者超过指定的时间量前,导致当前线程等待。   
  • wait(long timeout, int nanos)    //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
  • wait()    //用于让当前线程失去操作权限,当前线程进入等待序列
  • finalize()    //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

equals和==之间的区别

  • 双等号(==),比较的是他们的值
  • equals是比较堆中对象的内容是否相同,那么就要重写equals方法了。
  • hashcode方法只有在集合中用到,将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。 

“classloader加载机制,是否可以自己定义一个java.lang.String类,为什么?”

  • 不能!这里必须要提到java在加载类的过程。Java在加载类时,采用的是代理模式,即,类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,以此类推。在说明代理模式背后的原因之前,首先需要说明一下Java虚拟机是如何判定两个java类是相同的。Java虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同,才认为两个类时相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的,如果此时试图对这两个类的对象进行相互赋值,会抛出运行时异常ClassCastException。
  • 了解到这一点,就可以理解代理模式的设计动机了。代理模式是为了保证Java核心库的类型安全,所有的Java应用都至少需要引用java.lang.Object类,也就是说在运行时,java.lang.Object这个类需要被加载到Java虚拟机中。如果这个过程由Java应用自己的类加载器来完成的话,很可能就存在多个版本的java.lang.Object类,可是这些类之间是不兼容的。通过代理模式,对于Java核心库的类的加载工作由引导类加载器统一完成,保证了Java应用所使用的都是同一个版本的Java核心库的类,是相互兼容的。

 

“你知道哪几种创建线程类的方法(其实有好多,框架答出来肯定加分)“

  • Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
  • 1)继承Thread类创建线程
  • 2)实现Runnable接口创建线程
  • 3)使用Callable和Future创建线程
  • 4)使用Executor框架来创建线程池。

”数组与链表的相同点和不同点,为什么?“

对于快速访问数据,不经常有添加删除操作的时候选择数组实现,而对于经常添加删除数据,对于访问没有很高要求的时候选择链表。

”简述一下List、Set、Map的区别 “

List:1.可以允许重复的对象。

    2.可以插入多个null元素。

        3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。

        4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

Set:1.不允许重复对象

     2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。

        3. 只允许一个 null 元素

        4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

1.Map不是collection的子接口或者实现类。Map是一个接口。

2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。

3. TreeMap 也通过 Comparator  或者 Comparable 维护了一个排序顺序。

4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。

5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

2.面试题:什么场景下使用list,set,map呢?

(或者会问为什么这里要用list、或者set、map,这里回答它们的优缺点就可以了)

答:

  1. 如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。

  2. 如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。

  3. 如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。

  4. 如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。

”说出ArrayList,Vector, LinkedList的存储性能和特性“

  1. ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦

  2. LinkedList 采用的将对象存放在独立的空间中,而且在每个空间中还保存下一个链接的索引 但是缺点就是查找非常麻烦 要丛第一个索引开始

  3. ArrayList和Vector都是用数组方式存储数据,此数组元素数要大于实际的存储空间以便进行元素增加和插入操作,他们都允许直接用序号索引元素,但是插入数据元素涉及到元素移动等内存操作,所以索引数据快而插入数据慢.

  4. Vector使用了sychronized方法(线程安全),所以在性能上比ArrayList要差些.

  5. LinkedList使用双向链表方式存储数据,按序号索引数据需要前向或后向遍历数据,所以索引数据慢,是插入数据时只需要记录前后项即可,所以插入的速度快.

arraylist和vector的区别? 
1).同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程不安全的,不是同步的 
2).数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半

”对象序列化机制    Java 的序列化做什么用的 序列化id会出现哪些问题?”

序列化ID的作用:  

       其实,这个序列化ID起着关键的作用,它决定着是否能够成功反序列化!简单来说,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。等会我们可以通过代码验证一下。
 

       序列化ID如何产生:

       当我们一个实体类中没有显示的定义一个名为“serialVersionUID”、类型为long的变量时,Java序列化机制会根据编译时的class自动生成一个serialVersionUID作为序列化版本比较,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID。譬如,当我们编写一个类时,随着时间的推移,我们因为需求改动,需要在本地类中添加其他的字段,这个时候再反序列化时便会出现serialVersionUID不一致,导致反序列化失败。那么如何解决呢?便是在本地类中添加一个“serialVersionUID”变量,值保持不变,便可以进行序列化和反序列化。

“TCP、UDP,握手协议?”“Session, Cookie区别?时效?与浏览器有关?”

一、什么是TCP/IP和UDP协议

1、什么是TCP/IP协议

了解本概念之前我觉得可以了解一下什么是通信,两台计算机要通过网络进行通信,必须满足3条件

  • 协议(讲解)
  • 端口(讲解)
  • IP地址(讲解)

而TCP/IP协议是世界上应用最为广泛的协议,是以TCP和IP为为基础的不同层次上多个协议的集合,TCP协议俗称传输控制协议,是面向连接,需要三次握手建立连接,4次挥手断开连接报头最小长度20字节的协议

2、什么是UDP协议

UDP协议,用户数据包协议,面向无连接,报头只有8个字节。

“hibernate和ibatis区别?”“设计模式?”

hibernate和ibatis区别这里不作说明,这是必备的,不作多说明,自己概况。

设计模式可以参考这篇文章:https://www.cnblogs.com/geek6/p/3951677.html

“HashMap 、Hashtable和 HashSet的区别?哪个key可以为空?HashMap的内部实现机制,Hash是怎样实现的,什么时候ReHash”

HashTable和HashMap区别

区别一:继承的父类不同 
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。

区别二:线程安全性不同 
Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省情况下是非Synchronize的。

区别三:是否提供contains方法 
HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。 
Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。

**区别四:**key和value是否允许null值 
其中key和value都是对象,并且不能包含重复key,但可以包含重复的value。 
Hashtable中,key和value都不允许出现null值。 
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。 
PS:这个面试喜欢问。

区别五:哈希值的计算方法不同,Hashtable直接使用的是对象的hashCode,而HashMap则是在对象的hashCode的基础上还进行了一些变化。

区别六:内部实现使用的数组初始化和扩容方式不同,内存初始大小不同,HashTable初始大小是11,而HashMap初始大小是16

HashMap和HashSet的区别

HashSet实质

(1)HashSet是set的一个实现类,hashMap是Map的一个实现类,同时hashMap是hashTable的替代品(为什么后面会讲到). 
(2)HashSet以对象作为元素,而HashMap以(key-value)的一组对象作为元素,且HashSet拒绝接受重复的对象.HashMap可以看作三个视图:key的Set,value的Collection,Entry的Set。 这里HashSet就是其实就是HashMap的一个视图。 
HashSet内部就是使用Hashmap实现的,和Hashmap不同的是它不需要Key和Value两个值。 
往hashset中插入对象其实只不过是内部做了

集合加锁?那synchronized与static synchronized 的区别?

synchronized作用是对类的当前实例(对象加锁。可以使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁(Java 并发编程)。

synchronized代码块【synchronized(synObject)】使用起来比synchronized方法要灵活得多。因为也许一个方法中只有一部分代码只需要同步,如果此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就可以避免这个问题(同步对象或类属性),synchronized代码块可以实现只对需要同步的地方进行同步。

与Lock的区别1. synchronized是Java语言的关键字,因此是内置特性,Lock是一个类(java.util.concurrent.locks包),通过这个类可以实现同步访问;2. synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用。Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

static synchronized

每个类有一个锁,它可以用来控制对static数据成员的并发访问。访问static synchronized方法占用的是类锁,而访问非static synchronized方法占用的是对象锁

static synchronized控制类的所有实例(对象)的访问(相应代码块)。synchronized相当于 this.synchronized,static synchronized相当于Something.synchronized

web设计中forward() 与redirect()的区别?url怎么保存?参数怎么传递?

直接转发方式(Forward),客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。

  间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。

Tomcat的session共享机制 ?Tomcat优先加载什么库?为什么?

1、请求精确定位:session sticky,例如基于访问ip的hash策略,即当前用户的请求都集中定位到一台服务器中,这样单台服务器保存了用户的session登录信息,如果宕机,则等同于单点部署,会丢失,会话不复制。

2、session复制共享:session replication,如tomcat自带session共享,主要是指集群环境下,多台应用服务器之间同步session,使session保持一致,对外透明。 如果其中一台服务器发生故障,根据负载均衡的原理,调度器会遍历寻找可用节点,分发请求,由于session已同步,故能保证用户的session信息不会丢失,会话复制,。

Tomcat的class加载的优先顺序一览   
1.最先是$JAVA_HOME/jre/lib/ext/下的jar文件。   
2.环境变量CLASSPATH中的jar和class文件。   
3.$CATALINA_HOME/common/classes下的class文件。   
4.$CATALINA_HOME/commons/endorsed下的jar文件。   
5.$CATALINA_HOME/commons/i18n下的jar文件。   
6.$CATALINA_HOME/common/lib   下的jar文件。   
(JDBC驱动之类的jar文件可以放在这里,这样就可以避免在server.xml配置好数据源却出现找不到JDBC   Driver的情况。)   
7.$CATALINA_HOME/server/classes下的class文件。   
8.$CATALINA_HOME/server/lib/下的jar文件。   
9.$CATALINA_BASE/shared/classes   下的class文件。   
10.$CATALINA_BASE/shared/lib下的jar文件。   
11.各自具体的webapp   /WEB-INF/classes下的class文件。   
12.各自具体的webapp   /WEB-INF/lib下的jar文件。

struts2的实现原理/springmvc流程,两者区别?

面试题目总结一_第1张图片

  1. 用户发出一个HttpServletRequest请求。
  2. 这个请求经过一系列的过滤器Filter来传送。如果Struts2与Site Mesh插件以及其他框架进行了集成,则请求首先要可选的ActionContextCleanUp过滤器。
  3. 调用FilterDispatcher。FilterDispatcher时控制器的核心,他通过询问ActionMapper来确定该请求是否需要调用某个Action。如果需要调用某个Action,FilterDispatcher就把该请求转交给ActionProxy处理。
  4. ActionProxy通过配置管理器Configuration Manager询问框架的配置文件struts.xml,从而找到需要调用的Action类。
  5. ActionProxy创建一个ActionInvocation的实例,该实例使用命名模式来调用。在Action执行的前后,ActionInvocation实例根据配置文件加载与Action相关的所有拦截器Interceptor。
  6. 一旦Action执行完毕,ActionInvocation实例根据struts.xml文件中的配置找到相应的返回结果。返回结果通常是一个JSP或者FreeMarker的模板。
  7. 最后,HttpServletResponse响应通过web.xml文件中配置的过滤器返回。

面试题目总结一_第2张图片

具体步骤:

第一步:发起请求到前端控制器(DispatcherServlet)

第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)

第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略

第四步:前端控制器调用处理器适配器去执行Handler

第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler

第六步:Handler执行完成给适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)

第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可

第九步:视图解析器向前端控制器返回View

第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)

第十一步:前端控制器向用户响应结果

两者区别:

SpringMVC与Struts2区别与比较总结

一、框架机制

1、Struts2采用Filter(StrutsPrepareAndExecuteFilter)实现,SpringMVC(DispatcherServlet)则采用Servlet实现。
2、Filter在容器启动之后即初始化;服务停止以后坠毁,晚于Servlet。Servlet在是在调用时初始化,先于Filter调用,服务停止后销毁。

二、拦截机制

1、Struts2

a、Struts2框架是类级别的拦截,每次请求就会创建一个Action,和Spring整合时Struts2的ActionBean注入作用域是原型模式prototype(否则会出现线程并发问题),然后通过setter,getter吧request数据注入到属性。
b、Struts2中,一个Action对应一个request,response上下文,在接收参数时,可以通过属性接收,这说明属性参数是让多个方法共享的。
c、Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了
2、SpringMVC
a、SpringMVC是方法级别的拦截,一个方法对应一个Request上下文,所以方法直接基本上是独立的,独享request,response数据。而每个方法同时又何一个url对应,参数的传递是直接注入到方法中的,是方法所独有的。处理结果通过ModeMap返回给框架。
b、在Spring整合时,SpringMVC的Controller Bean默认单例模式Singleton,所以默认对所有的请求,只会创建一个Controller,有应为没有共享的属性,所以是线程安全的,如果要改变默认的作用域,需要添加@Scope注解修改。
三、性能方面
SpringMVC实现了零配置,由于SpringMVC基于方法的拦截,有加载一次单例模式bean注入。而Struts2是类级别的拦截,每次请求对应实例一个新的Action,需要加载所有的属性值注入,所以,SpringMVC开发效率和性能高于Struts2。

四、拦截机制
Struts2有自己的拦截Interceptor机制,SpringMVC这是用的是独立的Aop方式,这样导致Struts2的配置文件量还是比SpringMVC大。
五、配置方面
spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
SpringMVC可以认为已经100%零配置。
六、设计思想
Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。
七、集成方面
SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。

servlet/filter作用、原理、区别?

Filter可认为是Servlet的一种“变种”,它主要用于对用户请求进行预处理,
也可以对HttpServletResponse进行后处理,是个典型的处理链。它与Servlet的区别在于:它不能直接向用户生成响应。
完整的流程是:Filter对用户请求进行预处理,接着将请求交给 Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理
Filter必须实现javax.Servlet.Filter接口,并且必须定义以下三个方法:init(),destory(),doFilter().
Servlet一般继承HttpServlet,当Url匹配这个Servlet时候运行处理请求;
1,servlet 流程是短的,url传来之后,就对其进行处理,之后返回或转向到某一自己指定的页面。它主要用来在 业务处理之前进行控制.
2,filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等,而servlet 处理之后,不会继续向下传递。filter功能可用来保持流程继续按照原来的方式进行下去,或者主导流程,而servlet的功能主要用来主导流程。

项目中都用到了哪些设计模式?怎么用的?为什么用这个?

这个请自行处理。

二、Java多线程相关

  • 线程池的原理,为什么要创建线程池?创建线程池的方式;

  • 线程池作用就是限制系统中执行线程的数量。
         根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

    为什么要用线程池:

    1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

    2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

    Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

  • Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
  • 1)继承Thread类创建线程
  • 2)实现Runnable接口创建线程
  • 3)使用Callable和Future创建线程
  • 4)使用Executor框架来创建线程池。

  • 线程的生命周期,什么时候会出现僵死进程;

  • 1、线程的生命周期:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。 
    2、当线程对象调用了start()方法之后,该线程处于就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了。至于该线程何时开始运行,取决于JVM里线程调度器的调度。 
    3、启动线程使用start()方法,而不是run()方法。 
    4、只能对处于新建状态的线程调用start(),否则将引发IllegalThreadStateException异常。 
    5、所有现代的桌面和服务器操作系统都采用抢占式调度策略,只有当一个线程调用了它的sleep()方法或yield()方法后才会放弃所占用的资源。 
    6、线程从阻塞状态只能进入就绪状态,无法进入运行状态。 
    7、程序会以如下三种方式结束,结束后就处于死亡状态。 
    (1)run()或call()方法执行完成,线程正常结束。 
    (2)线程抛出一个未捕获的Exception或Error。 
    (3)直接调用该线程的stop()方法来结束该线程——该方法容易导致死锁,通常不推荐使用。 
    8、isAlive()方法测试某个线程是否已经死亡。
  • 说说线程安全问题,什么实现线程安全,如何实现线程安全;

  • 什么时候会出现线程安全问题?

      在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量、一个对象、一个文件、一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题:

  •  

    由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错。
  • 如何解决线程安全问题?

    基本上所有的并发模式在解决线程安全问题上,都采用“序列化访问临界资源”的方案,即在同一时刻,只能有一个线程访问临界资源,也称同步互斥访问。

     通常来说,是在访问临界资源的代码前面加上一个锁,当访问完临界资源后释放锁,让其他线程继续访问。

      在Java中,提供了两种方式来实现同步互斥访问:synchronized和Lock。

      本文主要讲述synchronized的使用方法,Lock的使用方法在下一篇博文中讲述。

  • Lock和synchronized区别?

  • synchronized是一个关键字,Lock是一个接口,是JDK1.5新特性.

  • synchronized代码块执行完成之后会自动释放锁对象,Lock必须手动调用方法释放锁对象。

  • synchronized代码块出现了异常也会自动释放锁对象,Lock接口中出现异常也需要手动释放锁对象。

  • 如果资源竞争不激烈时,使用synchronized或Lock接口的效率差不多,如果资源竞争很激烈,强烈推荐使用Lock接口。

  • 创建线程池有哪几个核心参数? 如何合理配置线程池的大小?

  • corePoolSize,线程池里最小线程数

    maximumPoolSize,线程池里最大线程数量,超过最大线程时候会使用RejectedExecutionHandler

    keepAliveTime,unit,线程最大的存活时间

    workerQueue,缓存异步任务的队列

    threadFactory,用来构造线程池里的worker线程

  • 如何配置线程?

  • 任务的性质:CPU密集型任务、IO密集型任务、混合型任务。
  • 任务的优先级:高、中、低。
  • 任务的执行时间:长、中、短。
  • 任务的依赖性:是否依赖其他系统资源,如数据库连接等。
  • volatile、ThreadLocal的使用场景和原理;

  • ThreadLocal是用于解决多线程共享类的成员变量,原理:在每个线程中都存有一个本地ThreadMap,相当于存了一个对象的副本,key为threadlocal对象本身,value为需要存储的对象值,这样各个线程之间对于某个成员变量都有自己的副本,不会冲突。
  • 2、volatile保证了成员变量在多线程下的可见性和有序性,不保证原子性,java中原子性的操作为读取一个值或者给一个变量赋值(例如 i=2)

    3、线程在执行完一行代码,例如修改了一个变量的值,因为工作内存速度小于主存中高速CPU的速度,所以对于其他的线程而言,读取到该变量的值可能不是最新的值。

    4、使用volatile关键字的时候,该变量一旦被修改,会立即写入到主存中,同时会让其他线程的工作内存中的缓存失效,这样,其他线程在访问该变量的时候会重新从主存中读取可以获得该变量最新的数据,从而保证的变量的可见性。

  • ThreadLocal什么时候会出现OOM的情况?为什么?

  • 什么是OOM OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. 意思就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。

    2)为什么会OOM?

    为什么会没有内存了呢?原因不外乎有两点:

    1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。

    2)应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。

    内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。

    内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。

  • synchronized、volatile区别、synchronized锁粒度、模拟死锁场景、原子性与可见性;

  • volatile与synchronized

    1)volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
    2)volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
    3)volatile仅能实现变量的修改可见性,而synchronized则可以保证变量的修改可见性和原子性.

      《Java编程思想》上说,定义long或double变量时,如果使用volatile关键字,就会获得(简单的赋值与返回操作)原子性
    4)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.

三、JVM相关

  • JVM内存模型,GC机制和原理;

  •  根据JVM规范,JVM把内存划分成了如下几个区域:

    1.方法区(Method Area)
    2.堆区(Heap)
    3.虚拟机栈(VM Stack)
    4.本地方法栈(Native Method Stack)
    5.程序计数器(Program Counter Register)

    GC机制

           随着程序的运行,内存中的实例对象、变量等占据的内存越来越多,如果不及时进行回收,会降低程序运行效率,甚至引发系统异常。

           在上面介绍的五个内存区域中,有3个是不需要进行垃圾回收的:本地方法栈、程序计数器、虚拟机栈。因为他们的生命周期是和线程同步的,随着线程的销毁,他们占用的内存会自动释放。所以,只有方法区和堆区需要进行垃圾回收,回收的对象就是那些不存在任何引用的对象。

  • GC分哪两种,Minor GC 和Full GC有什么区别?什么时候会触发Full GC?分别采用什么算法?

  • JVM里的有几种classloader,为什么会有多种?

  • JVM在运行时会产生三个ClassLoader:根装载器、ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。
  • 他们主要是分工不一样,各自负责不同的区域,另外也是为了实现委托模型。什么是委托模型呢,其实就是当类加载器有加载需求的时候,先请示他的父类使用父类的搜索路径来加入,如果没有找到的话,才使用自己的搜索路径来来搜索类
  • 什么是双亲委派机制?介绍一些运作过程,双亲委派模型的好处;

  • 双亲委派机制描述 
    某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
  •  
  • 什么情况下我们需要破坏双亲委派模型;

  • 常见的JVM调优方法有哪些?可以具体到调整哪个参数,调成什么值?

  • JVM虚拟机内存划分、类加载器、垃圾收集算法、垃圾收集器、class文件结构是如何解析的;

四、Java高级部分

  • 红黑树的实现原理和应用场景;

  • 红黑树是自平衡的二叉搜索树,是计算机科学中的一种数据结构。

    平衡是指所有叶子的深度基本相同(完全相等的情况并不多见,所以只能趋向于相等) 。

    二叉搜索树是指,节点最多有两个儿子,且左子树中所有节点都小于右子树。

    树中节点有改动时,通过调整节点顺序(旋转),重新给节点染色,使节点满足某种特殊的性质来保持平衡。

    旋转和染色过程肯定经过特殊设计可以高效的完成。

  • NIO是什么?适用于何种场景?

  • 1,IO是面向流的,NIO是面向块(缓冲区)的。

    IO面向流的操作一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。,导致了数据的读取和写入效率不佳;

  •  

    IO是阻塞的,NIO是非阻塞的。
  •  

    NIO和IO各适用的场景是什么呢?

    如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,这时候用NIO处理数据可能是个很好的选择。

    而如果只有少量的连接,而这些连接每次要发送大量的数据,这时候传统的IO更合适。使用哪种处理数据,需要在数据的响应等待时间和检查缓冲区数据的时间上作比较来权衡选择。

  • Java9比Java8改进了什么;

  • 1.新模块系统 2.支持HTTP/2.0 3.改进的Javadoc 4.Stream改进 5.使用新的工厂方法更容易地初始化Collections
  • 6.接口中的私有方法 7.语言和语法的改进 8.增强处理API 9.Java REPL = Jshell
  • HashMap内部的数据结构是什么?底层是怎么实现的?(还可能会延伸考察ConcurrentHashMap与HashMap、HashTable等,考察对技术细节的深入了解程度);

  • HashMap的数据结构

    数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。

  • 数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;
  • 链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。
  • 说说反射的用途及实现,反射是不是很慢,我们在项目中是否要避免使用反射;

  • 程序中一般的对象类型都是在编译期就确定下来的,而Java 反射机制可以动态的创建对象并调用其属性,这样对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象即使这个对象在编译期是未知的,
    反射的核心:是 JVM 在运行时 才动态加载的类或调用方法或属性,他不需要事先(写代码的时候或编译期)知道运行对象是谁。

  • 说说自定义注解的场景及实现;

  • List 和 Map 区别,Arraylist 与 LinkedList 区别,ArrayList 与 Vector 区别;

  • List:是存储单列数据的集合,存储的数据是有序并且是可以重复的 
    Map:存储双列数据的集合,通过键值对存储数据,存储 的数据是无序的,Key值不能重复,value值可以重复

五、Spring相关

  • Spring AOP的实现原理和场景?

  • AOP的核心概念

    AOP(Aspect Oriented Programming),是面向切面编程的技术。AOP基于IoC基础,是对OOP的有益补充,流行的AOP框架有Sping AOP、AspectJ

    AOP技术它利用一种称为“横切”的技术,剖解开封装的对象内部并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性

  •  

    什么时候该用AOP:

    假如业务模块一、二、三都需要日志记录,那么如果都在三个模块内写日志逻辑,那么会有两个问题: 
    1. 打破模块的封装性 
    2. 有很多重复代码 
    解决重复代码问题,可以通过封装日志逻辑为一个类,然后在各个模块需要的地方通过该类来试下日志功能,但是还是不能解决影响模块封装性的问题。 
    那么AOP就可以解决,它使用切面,动态地织入到各模块中(实际就是使用代理来管理模块对象),这样既解决了重复代码问题又不会影响模块的封装性

  •  

     

    Spring AOP的使用步骤

    一、定义具体业务逻辑模块(目标对象) 
    二、定义切面(即实现通知逻辑) 
    三、实现切面逻辑

  • Spring bean的作用域和生命周期;

  •  创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的“配方”。把bean定义看成一个配方很有意义,它与class很类似,只根据一张“处方”就可以创建多个实例。不仅可以控制注入到对象中的各种依赖和配置值,还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域,而不必在Java Class级定义作用域。
  • bean的生命周期流程图:

  • Spring Boot比Spring做了哪些改进? Spring 5比Spring4做了哪些改进;

  • 1、众所周知Spring框架需要进行大量的配置Spring Boot引入自动配置的概念让项目设置变得很容易Spring Boot本身并不提供Spring框架的核心特性以及扩展功能只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。

    2、也就是说它并不是用来替代Spring的解决方案而是和Spring框架紧密结合用于提升Spring开发者体验的工具。

    4、同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)大部分的Spring Boot应用都只需要非常少量的配置代码开发者能够更加专注于业务逻辑。

    5、Spring Boot只是承载者辅助你简化项目搭建过程的如果承载的是WEB项目,使用Spring MVC作为MVC框架那么工作流程和你上面描述的是完全一样的因为这部分工作是Spring MVC做的而不是Spring Boot。

    6、对使用者来说换用Spring Boot以后项目初始化方法变了,配置文件变了另外就是不需要单独安装Tomcat这类容器服务器了maven打出jar包直接跑起来就是个网站但你最核心的业务逻辑实现与业务流程实现没有任何变化。

  • Spring Framework 5.0 的功能可以分为:这里也只是做一个简单的介绍,具体请自行学习研究。

  • JDK 基线更新

  • 核心框架修正

  • 核心容器更新

  • 含 Kotlin 在内的函数式编程

  • 响应式编程模型

  • 测试改进

  • 库支持

  • 中止支持

  • 如何自定义一个Spring Boot Starter?

  • Spring IOC是什么?优点是什么?

  • Ioc(Inversion of control)控制反转,这里的控制指把控制权从应用程序中剥离出来。ioc它可以把创建对象和查找依赖对象的权限交给Ioc容器控制,而不是传统的由这些对象的使用方(消费者)进行创建初始化操作。IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则。

    为什么Ioc叫控制反转呢,反转了什么呢?传统的程序都是消费者主动创建对象,现在容器帮我们查找及注入依赖对象,而消费者只是被动的接受依赖对象,此为反转。

  • SpringMVC、动态代理、反射、AOP原理、事务隔离级别;

六、中间件篇

  • Dubbo完整的一次调用链路介绍;

  • Dubbo支持几种负载均衡策略?

  • Dubbo Provider服务提供者要控制执行并发请求上限,具体怎么做?

  • Dubbo启动的时候支持几种配置方式?

  • 了解几种消息中间件产品?各产品的优缺点介绍;

  • 消息中间件如何保证消息的一致性和如何进行消息的重试机制?

  • Spring Cloud熔断机制介绍;

  • Spring Cloud对比下Dubbo,什么场景下该使用Spring Cloud?

七、数据库篇

  • 锁机制介绍:行锁、表锁、排他锁、共享锁;

  • 乐观锁的业务场景及实现方式;

  • 事务介绍,分布式事物的理解,常见的解决方案有哪些,什么事两阶段提交、三阶段提交;

  • MySQL记录binlog的方式主要包括三种模式?每种模式的优缺点是什么?

  • MySQL锁,悲观锁、乐观锁、排它锁、共享锁、表级锁、行级锁;

  • 分布式事务的原理2阶段提交,同步\异步\阻塞\非阻塞;

  • 数据库事务隔离级别,MySQL默认的隔离级别、Spring如何实现事务、JDBC如何实现事务、嵌套事务实现、分布式事务实现;

  • SQL的整个解析、执行过程原理、SQL行转列;

八、Redis

  • Redis为什么这么快?redis采用多线程会有哪些问题?

  • Redis支持哪几种数据结构;

  • Redis跳跃表的问题;

  • Redis单进程单线程的Redis如何能够高并发?

  • Redis如何使用Redis实现分布式锁?

  • Redis分布式锁操作的原子性,Redis内部是如何实现的?

问题蛮多的,又是夜深了,博主这里,准备休息了,下次再整理更新..................

你可能感兴趣的:(面试题目大全)