公众号|松花皮蛋的黑板报|Java业务开发易错点
松花皮蛋的黑板报
  • 分享在京东工作的技术感悟,还有JAVA技术和业内最佳实践,大部分都是务实的、能看懂的、可复现的

扫一扫
关注公众号

Java业务开发易错点

博客首页文章列表 松花皮蛋me 2020-03-25 23:46

一、并发工具类库


1、没有显式使用多线程技术并不代表不存在线程安全的隐患,比如:使用Tomcat容器。


2、使用线程间隔离而在方法或类共享的工具后需要显式进行清理,比如:使用ThreadLocal工具。


3、单个操作是线程安全的,但是不代表多个组合是安全的。比如:先后使用ConcurrentHashMap的Get和Put方法。


4、要充分理解工具库的特性,让其在合适的场景下发挥真正的作用。比如:使用ConcurrentHashMap的putIfAbsent代替Get\Put组合操作,再比如:数据变化频繁的情况不要使用CopyOnWrite技术。


二、并发锁


1、没有分析清楚线程、业务逻辑、锁三者关系随意加锁,导致加锁无效。比如:比较操作在字节码层面是三步,代码看似一行但也不是原子性的。


2、没有搞清楚锁和需要保护的对象是不是一个层面的,导致加锁失败。比如:静态字段属于类,类级别的类才有用,非静态字段属于类实例,实例级别的锁才有用。


3、要注意锁对象的粒度。必要时考虑读写锁和乐观锁,甚至能不用锁就不要用锁。


4、多把锁要小心死锁问题。比如:加锁时没有注意顺序,导致循环等待资源释放。


5、加锁时要考虑锁超时的场景,避免到期自动释放,其他线程从而获取相同的锁然后执行重复的逻辑。比如:单独启动一个线程来避免锁的超时、保证业务支持幂等操作。


6、要避免误用锁导致性能吞吐量下降。比如:通过压测排除锁误用引起的性能问题。

三、线程池


1、不要使用底层为无界队列的线程池。比如:使用Executors 框架快速创建newFixedThreadPool ,存在OOM隐患。


2、线程池要可控,要确保能满足预期。比如:使用有意义的线程名、设定好拒绝策略、设定好回收策略等。


3、区分业务场景合理线程池。比如:IO密集型和CPU计算型业务的线程池中线程属性应该是不同的。


4、不要盲目复用他人的线程池业务代码,容易导致相互干扰。


四、连接池


1、要正确鉴别连接池的实现方式,到底是池和连接分离,还是内置连接池。


2、确保连接池是复用的,确保程序退出前显式关闭连接释放资源。


3、要做好最大连接数的监控报警,并结合业务容量规划及时调整。


4、要注意线程安全问题,避免导致数据错乱。比如:在多线程场景下使用JRedis操作redis对象是线程不安全的。


五、HTTP请求中的超时、重试


1、连接和读取数据超时时间不宜设置过长,正常1~3秒左右即可。


2、要利用好框架内置的重试逻辑,同时也要注意隐含的重试配置。比如:接口不支持幂等性POST请求,但是Spring Cloud Feign框架在请求超时后自动地进行了重试。


五、事务


1、不使用特殊配置或者动态织入时,在私有方法中使用事务注解不会生效,因为JDK动态代理默认通过继承增强,私有方法对其不可见。


2、使用this自调用事务方法是不会生效的。正确做法是注入self,再通过它调用。


3、默认情况下,出现非受检异常或者Error错误时,才会触发Spring事务回滚。


4、我们可以设置事务传播策略,保证子流程出现异常只有它自身回滚,而不会影响主流程。


5、不要在入口处依次调用不同的事务方法。

六、数值计算


1、对于数据很敏感的场景,比如金融类,需要使用浮点数来表示,那么就尽量使用BigDecimal。另外还要注意BigDecimal的构造方式,使用浮点数作为构造参数会出现精度缺失。


2、使用大数类计算工具时,应该自始至终地使用它,而不是声明时使用但是计算、比较时却使用传统方法。


3、浮点数格式化时需要避免四舍五入,数值累加时需要避免溢出。

七、读写分离


使用读写分离的架构下,主库更新完立即去从库读取数据,有时候会被同步延迟影响到,正常做法是避免立即去读。比如订单支付后跳到一个轻量级的支付成功页,而不是订单列表页。


八、分库分表


分库分表的目的是减少单表数据存储量,唯一的做法是使用主键进行分片,从而减少数据倾斜,避免热点问题。其他使用范围或者非主键进行分片都是耍流氓,拿起石头砸自己的脚。


九、集合类操作


1、需要注意构造或者切割时得到的可能只是原始视图,共享存储了原始对象,而不是新的对象,如果再基于视图进行增删改查很容易出现异常,甚至是内存溢出。比如Arrays.asList方法,再比如List的subList方法。


2、根据场景选择合适的数据结构,但是需要注意时间复杂度和空间复杂度。比如能使用HashMap进行搜索就不要使用ArrayList进行搜索,再比如链表LinkedList的插入效率就不如List的。

十、空值处理


空值的正确处理以及避免空指针异常,绝不是判空这么简单,还要根据业务属性从前到后仔细考虑。比如我们要避免把数据库字段错误地重置为空值,不然就会出现逻辑处理的不一致性。再比如数据库字段值为NULL时,使用sum、count函数计算时存在坑点。

推荐阅读

    阅读 87 次