一.基础注意
1.属性不能起isDelete(以is开头,有些框架会序列化错误)
2.set里面自定义对象必须重写equal和hashCode方法
3.Map的自定义对象作为key,必须重写equal和hashCode方法
4.集合转数组要用toArray(T[ ] array)带参数的方法,大小是list.size()
5.hashMap<>(16)要设置初始容量为16,不然会影响性能
6.任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。
二.编程并发
1.线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool :
允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
2) CachedThreadPool 和 ScheduledThreadPool :
允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。
2.SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为
static ,必须加锁,或者使用 DateUtils 工具类。
正例:注意线程安全,使用 DateUtils 。亦推荐如下处理:
private static final ThreadLocal
@ Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
3.线程一需要对表 A 、 B 、 C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序
也必须是 A 、 B 、 C ,否则可能出现死锁
4.使用 CountDownLatch 进行异步转同步操作,每个线程退出前必须调用 countDown
方法,线程执行代码注意 catch 异常,确保 countDown 方法被执行到,避免主线程无法执行
至 await 方法,直到超时才返回结果。
说明:注意,子线程抛出异常堆栈,不能在主线程 try - catch 到。
5.避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一
seed 导致的性能下降。
说明: Random 实例包括 java . util . Random 的实例或者 Math . random() 的方式。
正例:在 JDK 7 之后,可以直接使用 API ThreadLocalRandom ,而在 JDK 7 之前,需要编码保
证每个线程持有一个实例
6.volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题,
但是如果多写,同样无法解决线程安全问题。如果是 count ++操作,使用如下类实现:
AtomicInteger count = new AtomicInteger(); count . addAndGet( 1 ); 如果是 JDK 8,推
荐使用 LongAdder 对象,比 AtomicLong 性能更好 ( 减少乐观锁的重试次数 )
7.HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,在
开发过程中可以使用其它数据结构或加锁来规避此风险
8.ThreadLocal 无法解决共享对象的更新问题, ThreadLocal 对象建议使用 static
修饰。这个变量是针对一个线程内所有操作共享的,所以设置为静态变量,所有此类实例共享
此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象 ( 只
要是这个线程内定义的 ) 都可以操控这个变量。
9.在高并发场景中,避免使用”等于”判断作为中断或退出的条件。
说明:如果并发控制没有处理好,容易产生等值判断被“击穿”的情况,使用大于或小于的区间
判断条件来代替。
反例:判断剩余奖品数量等于 0 时,终止发放奖品,但因为并发处理错误导致奖品数量瞬间变
成了负数,这样的话,活动无法终止。
三.控制语句
1.表达异常的分支时,少用 if-else 方式 ,这种方式可以改写成:
if (condition) {
...
return obj;
}
// 接着写 else 的业务逻辑代码;
说明:如果非得使用 if()...else if()...else... 方式表达逻辑,【强制】避免后续代码维
护困难,请勿超过 3 层。
正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现
2.除常用方法(如 getXxx/isXxx )等外,不要在条件判断中执行其它复杂的语句,将
复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。
说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么
样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?
正例:
// 伪代码如下
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}
反例:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}
四.异常处理
1.异常不要用来做流程控制,条件控制。
说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式
要低很多。
2.使用 JDK8 的 Optional 类来防止 NPE 问题
五.日志处理
1.正例: ( 占位符 )
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
2.避免重复打印日志,浪费磁盘空间,务必在 log 4 j . xml 中设置 additivity = false 。
正例:
六.数据库
1.单表行数超过 500 万行或者单表容量超过 2 GB ,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。