常见面试流程
- 技术相关 - java语言(基本、容器、多线程、异常处理、JVM)
- 设计模式
- Spring
- MySQL、Redis等(JDBC)
- 前端相关
- Shell相关
- 算法题
 
- 项目相关 
Java语言基础
面向对象
- 绝对不能在构造函数中调用会被Override的函数
- QA:builder模式与Config类(InstanceSpec)取舍? builder需要创建静态类
- QA:构造函数什么时候可以抛异常?
- Q:init私有方法什么时候使用? A:构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中
String使用
- 判断是否相等绝对不能直接使用”==”进行,可以使用equals方法
- 判断是否为空: StringUtils.isBlank(),Str.isEmpty(),Str.length()==0
- 循环体内,字符串的联接方式,使用 StringBuilder的append方法进行扩展
集合使用
- Array初始化1 new ArrayList<Element>(Arrays.asList(array)) 
使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出 UnsupportedOperationException异常。
- 使用集合转数组的方法,必须使用集合的 - toArray(T[] array),传入的是类型完全一样的数组,大小就是- list.size()。
- ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 
- QA:集合接口的区别 list collection hashmap 
- 不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁 
- 高度注意Map类集合 K/V 能不能存储 - null值的情况- | 集合类 | Key | Value | Super | 说明 | 
 | —————– | ——— | ——— | ———– | —– |
 | Hashtable | 不允许为 null | 不允许为 null | Dictionary | 线程安全 |
 | ConcurrentHashMap | 不允许为 null | 不允许为 null | AbstractMap | 分段锁技术 |
 | TreeMap | 不允许为 null | 允许为 null | AbstractMap | 线程不安全 |
 | HashMap | 允许为 null | 允许为 null | AbstractMap | 线程不安全 |
- 利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作 
Exception处理
- 标准Exception分为两种expcetion,一种继承自RunTimeException,不需要方法捕捉,比如NullPointerException,IllegalStateException;另一种必须catch或throws,比如InterruptedException
- 推荐使用Preconditions.checkNotNull等工具
- catch后的代码仍然会执行,返回值与抛出异常都需要满足匹配,try中抛出的异常就会被对应catch捕获,上一个catch中抛出也会被下一个catch捕获,如果分支继续抛异常来结束那么该分支可以忽略返回值
 处理方法:1. 异常转义;2. 异常链接getCause
- 单元测试函数应该抛出任何异常
- 利用jdk7新语法自动关闭文件流 - 1 
 2
 3- try(InputStream is = new FileInputStream){ 
 //文件操作
 }
- 对No such method error处理:打印出具体绑定类 - 1 - <Object>.class.getProtectionDomain(); 
注释处理
- Bean注入
 @Autowired
 ApplicationContext ac;
 lockAnnotation = (LockAnnotation)ac.getBean(“LockAnnotation”)
- @Service与@Resouce可以配合使用
 http://bit1129.iteye.com/blog/2114126
- AOP
 http://www.xdemo.org/springmvc-aop-annotation/
多线程
- 后台定时任务 - 1 
 2
 3
 4
 5- //start 
 ScheduledExecutorService excutor = Excutor.newSingleThreadScheduledExecutor();
 excutor.scheduleWithFixedDelay(runnable, time);
 //end
 excutor.shutdown(); //excutor.shutdownNow();
- 线程池 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- List<Future<Object>> threads = Lists.newArrayList(); 
 ExcutorService excutor = Excutors.newCachedThreadPool();
 Future<Object> t = executor.submit(new Callable<Object>() {
 @Override
 public Object call() throws Exception {
 //do sth here!
 return null;
 }
 });
 threads.add(t);
 for(Future<Object> t: threads)
 t.get();
- CountDownLatch与Semaphore使用 - CountDownLatch设置初始值,调用 - wait()方法会阻塞直到被- notify()方法唤醒;调用- countDown()来减少值;创建时不会阻塞,需要调用- await()阻塞直至计数值为0;该机制被设计为只会触发一次,因此不会有方法来还原初始值。- Semaphore设置初始值,调用 - acquire()方法减少该值否则阻塞直至计数值大于0,调用- release(num)来增加值,调用- availablePermits()判断是否阻塞
- 单例模式注意使用double check方法 
| 1 | public Helper getHelper() { | 
Q:该模式有失效的可能? A:可参考 The “Double-Checked Locking is Broken” Declaration,推荐问题
解决方案中较为简单一种(适用于 JDK5 及以上版本),将目标属性声明为 volatile 型。
- executor 重要的三个参数含义 
 corePoolSize, maxmumPoolSize, [keepAliveTime], BlockingQueue
- 多线程的方法 
JVM
- 有哪些垃圾回收器 优缺点
- 四种导致full gc场景
- 持久代满了,gc不成功则out of memory
- 旧生代满了
- 新生代向S0和S1转移数据,S0和S1向旧生代转移数据,两边内存都设置较小,持续进行导致
- 直接system.gc
- Q: 原子变量实现? 设置unsafe 内存交换
- 给 JVM 设置-XX:+HeapDumpOnOutOfMemoryError 参数,让 JVM 碰到 OOM 场景时输出 dump 信息。
JDBC
- Q: 何时使用乐观锁 悲观锁 出现场景,jdbc事务提交使用哪种锁(一般使用DB的悲观锁)
Spring
调优:tcp窗口,事务大小
- 常用模块
 aop, aspects, beans, core, context, expression, orm, jdbc, jms, tx, test, web, webmvc
- 主要接口 
- 五种事务传播性Propagation 
 required, supports, mandatory, requires_new, not_supported, never, nested
netty
结构 lf缺陷
MySQL
- 设置AUTO_INCREMENT
 http://www.searchdatabase.com.cn/showcontent_38510.htm
- 使用datetime或timestamp类型,查询范围写法:send_time <= ‘2015-09-24 15:24:16’ - 区别:首先 DATETIM和TIMESTAMP类型所占的存储空间不同,前者8个字节,后者4个字节,这样造成的后果是两者能表示的时间范围不同。前者范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59,后者范围为1970-01-01 08:00:01到2038-01-19 11:14:07。所以可以看到TIMESTAMP支持的范围比DATATIME要小,容易出现超出的情况. 
 其次,TIMESTAMP类型在默认情况下,insert、update 数据时,TIMESTAMP列会自动以当前时间(CURRENT_TIMESTAMP)填充/更新。
 第三,TIMESTAMP比较受时区timezone的影响以及MYSQL版本和服务器的SQL MODE的影响
 所以一般来说,我比较倾向选择DATETIME,至于你说到索引的问题,选择DATETIME作为索引,如果碰到大量数据查询慢的情况,也可以分区表解决。
 最佳实践: 只要用int类型存格林时间的unix timestamp值就好了,使用TIMESTAMP主要是为了方便记current_timestamp
- 使用txt类型取代nvarchar 
 SQLserver 中使用nvarchar存储变长unicode字符串
- 使用tinyint(8)或bool(1)取代bit类型, int(32), bigint(64)
- DEFAULT 为0,则可以查询’’(空字符串);DEFAULT为NULL,则查询’’(空字符串)不匹配
- 业务ID自增设计insert msgId into [table] value(select max(msgId) from [table] + 1)
 这里max函数会导致锁表
 解决方法:单记一个max version表,利用行锁进行多线程同步
- 当发生Too many connections时,即使是DBA也无法登录到数据库,一般的做法是修改配置文件的max_connections参数,然后重启数据库,这样业务就有几秒钟的中断。
 还有一个hack的方法,用过gdb直接修改mysqld内存中max_connections的值,具体做法如下:gdb -ex "set max_connections=5000" -batch -p 'pgrep -x mysqld'
- 小数类型为 decimal,禁止使用 float 和 double。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
- 表必备三字段:id, gmt_create, gmt_modified。
- 不得使用外键与级联,一切外键概念必须在应用层解决。更禁止使用存储过程。
JBOSS
调优方法
- connector 改为Nio
- 使用G1回收器,+UseG1GC 提供一种计算方法预期最大停止时间
- 调整内存使用
Nginx
运用功能 模块实现 核心组件 upstream配置
- 高并发服务器建议调小 TCP 协议的 time_wait 超时时间,变更/etc/sysctl.conf 文件:net.ipv4.tcp_fin_timeout = 30
Redis
- 连接数
- 集群设置 集群算法
Curator
- 使用InterProcessMutex中的RevocationListener因为在另一个专用线程因此没法直接调用release释放,Revoke唤醒需要使用对应的lock节点而不是目录
 QA:这个设计很奇怪,按常理revoke应该调用在lock的path上然后自动通知当前获得锁的lock结构,并且应该有方法允许释放【可能状态比较难统一】
- 2.9版本之后可以自动清理锁目录,需要设置container.checkIntervalMs
- 共享锁实现
 http://www.tuicool.com/articles/yQBVfeA
- start方法只能在初始化后调用一次,close调用后只能销毁
Dubbo
- 使用transient关键字保证成员不被串行化
实现思路
1. WS服务转RPC
分为两个难点:wsdl信息提取,RPC服务端的API生成
wsdl信息提取:例如从BPM提取出ReceiveMsg方法与参数
RPC服务端API生成:
http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-API%E9%85%8D%E7%BD%AE
API方法所依赖的接口service与实现serviceImpl可以使用通用的泛化实现接口与实现
http://dubbo.io/Generic+Implementation-zh.htm
2. RPC服务转WS
分为两个难点:参考Dubbo客户端实现RPC客户端自动生成,WS服务端API生成
RPC信息提取:
WS服务端API生成: