Java面试时公司挑选职工的一种重要的方法,要想在Java面试中脱颖而出,超越竞争对手,必须做好面试准备以及面试资料,做好齐全的准备——这里分享一些常见的Java面试问题,主要有Java基础知识,集合容器,并发,jvm知识,spring全家桶,mybatis框架,数据库等。

1、Parallel Old 收集器(多线程标记整理算法)

Parallel Old 收集器是Parallel Scavenge的年老代版本,使用多线程的标记-整理算法,在 JDK1.6才开始提供。

在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量, Parallel Old 正是为了在年老代同样提供吞吐量优先的垃圾收集器, 如果系统对吞吐量要求比较高,可以优先考虑新生代Parallel Scavenge和年老代 Parallel Old 收集器的搭配策略。

2、对象分配内存是否线程安全?

对象创建十分频繁,即使修改一个指针的位置在并发下也不是线程安全的,可能正给对象 A 分配内存,指针还没来得及修改,对象 B 又使用了指针来分配内存。

解决方法:① CAS 加失败重试保证更新原子性。② 把内存分配按线程划分在不同空间,即每个线程在 Java 堆中预先分配一小块内存,叫做本地线程分配缓冲 TLAB,哪个线程要分配内存就在对应的 TLAB 分配,TLAB 用完了再进行同步。

3、当一个线程进入某个对象的一个synchronized的实例方法后,其它线程是否可进入此对象的其它方法?

如果其他方法没有synchronized的话,其他线程是可以进入的。

所以要开放一个线程安全的对象时,得保证每个方法都是线程安全的。

4、Serial 与 Parallel GC 之间的不同之处?

Serial 与 Parallel 在 GC 执行的时候都会引起 stop-the-world。它们之间主要不同 serial 收集器是默认的复制收集器,执行 GC 的时候只有一个线程,而parallel 收集器使用多个 GC 线程来执行。

5、为什么线程通信的方法 wait(), notify()和 notifyAll()被定义在 Object 类里?

因为Java所有类的都继承了Object,Java想让任何对象都可以作为锁,并且 wait(),notify()等方法用于等待对象的锁或者唤醒线程,在 Java 的线程中并没有可供任何对象使用的锁,所以任意对象调用方法一定定义在Object类中。

有的人会说,既然是线程放弃对象锁,那也可以把wait()定义在Thread类里面啊,新定义的线程继承于Thread类,也不需要重新定义wait()方法的实现。然而,这样做有一个非常大的问题,一个线程完全可以持有很多锁,你一个线程放弃锁的时候,到底要放弃哪个锁?当然了,这种设计并不是不能实现,只是管理起来更加复杂。

6、redux异步中间件之间的优劣?

redux-thunk优点:

1、 体积小: redux-thunk的实现方式很简单,只有不到20行代码

2、 使用简单: redux-thunk没有引入像redux-saga或者redux-observable额外的范式,上手简单

redux-thunk缺陷:

1、 样板代码过多: 与redux本身一样,通常一个请求需要大量的代码,而且很多都是重复性质的

2、 耦合严重: 异步操作与redux的action偶合在一起,不方便管理

3、 功能孱弱: 有一些实际开发中常用的功能需要自己进行封装

redux-saga优点:

1、 异步解耦: 异步操作被被转移到单独 saga.js 中,不再是掺杂在 action.js 或 component.js 中

2、 action摆脱thunk function: dispatch 的参数依然是一个纯粹的 action (FSA),而不是充满 “黑魔法” thunk function

3、 异常处理: 受益于 generator function 的 saga 实现,代码异常/请求失败 都可以直接通过 try/catch 语法直接捕获处理

4、 功能强大: redux-saga提供了大量的Saga 辅助函数和Effect 创建器供开发者使用,开发者无须封装或者简单封装即可使用

5、 灵活: redux-saga可以将多个Saga可以串行/并行组合起来,形成一个非常实用的异步flow

6、 易测试,提供了各种case的测试方案,包括mock task,分支覆盖等等

redux-saga缺陷:

1、 额外的学习成本: redux-saga不仅在使用难以理解的 generator function,而且有数十个API,学习成本远超redux-thunk,最重要的是你的额外学习成本是只服务于这个库的,与redux-observable不同,redux-observable虽然也有额外学习成本但是背后是rxjs和一整套思想

2、 体积庞大: 体积略大,代码近2000行,min版25KB左右

3、 功能过剩: 实际上并发控制等功能很难用到,但是我们依然需要引入这些代码

4、 ts支持不友好: yield无法返回TS类型

redux-observable优点:

1、 功能最强: 由于背靠rxjs这个强大的响应式编程的库,借助rxjs的操作符,你可以几乎做任何你能想到的异步处理

2、 背靠rxjs: 由于有rxjs的加持,如果你已经学习了rxjs,redux-observable的学习成本并不高,而且随着rxjs的升级redux-observable也会变得更强大

redux-observable缺陷:

1、 学习成本奇高: 如果你不会rxjs,则需要额外学习两个复杂的库

2、 社区一般: redux-observable的下载量只有redux-saga的1/5,社区也不够活跃,在复杂异步流中间件这个层面redux-saga仍处于领导地位

关于redux-saga与redux-observable的详细比较可见此链接

最近在备战面试的过程中,整理一下面试题。大多数题目都是自己手敲的,网上也有很多这样的总结。自己感觉总是很乱,所以花了很久把自己觉得重要的东西总结了一下。

7、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?

双亲委托模型的重要用途是为了解决类载入过程中的安全性问题。

1、 假设有一个开发者自己编写了一个名为java.lang.Object的类,想借此欺骗JVM。现在他要使用自定义ClassLoader来加载自己编写的java.lang.Object类。

2、 然而幸运的是,双亲委托模型不会让他成功。因为JVM会优先在Bootstrap ClassLoader的路径下找到java.lang.Object类,并载入它

Java的类加载是否一定遵循双亲委托模型?

1、 在实际开发中,我们可以通过自定义ClassLoader,并重写父类的loadClass方法,来打破这一机制。

2、 SPI就是打破了双亲委托机制的(SPI:服务提供发现)。

8、Hibernate中Session的load和get方法的区别是什么?

如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。

get方法直接返回实体类对象,load方法返回实体类对象的代理。

在Hibernate 3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate 3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。

9、说一下堆内存中对象的分配的基本策略

eden区、s0区、s1区都属于新生代,tentired 区属于老年代。大部分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden区->Survivor 区后对象的初始年龄变为1),当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。另外,大对象和长期存活的对象会直接进入老年代。

10、Java 中如何将字符串转换为整数?

String s="123";

int i;

第一种方法:i=Integer.parseInt(s);

第二种方法:i=Integer.valueOf(s).intValue();