缺陷 & 规避

  1. NPE 空指针异常(Null Pointer Exception)

1)使用注解 @NotNull 和 @Nullable

2)用 Optional 处理链式调用

3)用 Objects.equals(a,b) 代替 a.equals(b),能够避免任意对象为 null 时的 NPE。

4)使用空对象模式,空对像模式通过一个特殊对象代替不存在的情况,代表对象不存在时的默认行为模式。例如:用 Empty List 代替 null,EmptyList 能够正常遍历:Collections.emptyList();

  1. 线程安全

JVM 的内存模型十分复杂,难以理解, <<Java 并发编程实战>>告诉我们,除非你对 JVM 的线程安全原理十分熟悉,否则应该严格遵守基本的 Java 线程安全规则,使用 Java 内置的线程安全的类及关键字。

熟练使用线程安全类 ConcurrentHashMap

java 复制代码
public class ConcurrentHashMapExample {
    private Map<String, String> map = new ConcurrentHashMap<>();

    public void append(String key, String suffix) {
        // 使用 computeIfPresent 原子操作
        map.computeIfPresent(key, (k, v) -> v + suffix);
    }
}

保证变更的原子性

使用不可变对象

**正确性优先于性能:**不要因为担心性能问题而放弃使用 synchronized,volatile 等关键字,或者采用一些非常规写法。

多线程环境中的volatile:在多线程编程中,每个线程可以拥有变量的独立拷贝,这可能导致数据不一致的问题。声明一个变量为volatile可以保证所有线程看到的都是主存中的最新版本,从而在一定程度上解决了线程间可见性的问题。尽管volatile不保证复合操作的原子性,它通过内存屏障来防止指令重排序,确保了操作的顺序性。

Java中的volatile:在Java中,volatile不仅保证了单个变量的可见性,还可以用于实现轻量级的同步,特别是在使用双重检查锁定模式(Double-Checked Locking)设计单例模式时。volatile关键字通过内存屏障来防止指令重排,这对于维持对象引用的可见性和一致性至关重要。

线程池使用不当

java 复制代码
public class ThreadPoolExample {

    // 没有任何限制的线程池, 使用起来很方便, 但当一波请求高峰到达时, 可能会创建大量线程, 导致系统崩溃
    private static Executor executor = Executors.newCachedThreadPool();

}

手动创建线程池

java 复制代码
public class ManualCreateThreadPool {

    // 手动创建资源有限的线程池
    private Executor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1000),
        new ThreadFactoryBuilder().setNameFormat("work-%d").build());
}

通过 AOP 统一异常处理

  1. 避免未知异常抛给调用方, 将未知异常转为 Result 或者通用异常类型

  2. 统一异常日志的打印和监控

处理 Checked Exception

Checked Exception 是在编译期要求必须处理的异常,也就是非 RuntimeException 类型的异常,但 Java Checked 的异常给接口的调用者造成了一定的负担,导致异常声明层层传递,如果顶层能够处理该异常,我们可以通过 lombok 的 @SneakyThrows 注解规避 Checked exception。

Try catch 线程逻辑

特殊异常的处理

InterruptedException 一般是上层调度者主动发起的中断信号,例如某个任务执行超时,那么调度者通过将线程置为 interuppted 来中断任务,对于这类异常我们不应该在 catch 之后忽略,应该向上抛出或者将当前线程置为 interuppted。

避免 catch Error

不要吞并 Error,Error 设计本身就是区别于异常,一般不应该被 catch,更不能被吞掉。举个例子,OOM 有可能发生在任意代码位置,如果吞并 Error,让程序继续运行,那么以下代码的 start 和 end 就无法保证一致性。

内存/资源泄漏

虽然 JVM 有垃圾回收机制,但并不意味着内存泄漏问题不存在,一般内存泄漏发生在在长时间持对象无法释放的场景,比如静态集合,内存中的缓存数据,运行时类生成技术等。

Spring 事务问题,注意事务注解失效的场景

当打上 @Transactional 注解的 spring bean 被注入时,spring 会用事务代理过的对象代替原对象注入。

但是如果注解方法被同一个对象中的另一个方法里面调用,则该调用无法被 Spring 干预,自然事务注解也就失效了。

java 复制代码
 @Component
 public class TransactionNotWork {
 ​
     public void doTheThing() {
         actuallyDoTheThing();
     }
 ​
     @Transactional
     public void actuallyDoTheThing() {
     }
 }
相关推荐
9***P3347 分钟前
PHP代码覆盖率
开发语言·php·代码覆盖率
8***293110 分钟前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
CoderYanger13 分钟前
优选算法-栈:67.基本计算器Ⅱ
java·开发语言·算法·leetcode·职场和发展·1024程序员节
碧海潮生_CC23 分钟前
【CUDA笔记】04 CUDA 归约, 原子操作,Warp 交换
笔记·cuda
jllllyuz28 分钟前
Matlab实现基于Matrix Pencil算法实现声源信号角度和时间估计
开发语言·算法·matlab
q***062934 分钟前
Tomcat的升级
java·tomcat
多多*43 分钟前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven
青云交1 小时前
Java 大视界 -- Java 大数据在智能物流无人配送车路径规划与协同调度中的应用
java·spark·路径规划·大数据分析·智能物流·无人配送车·协同调度
摇滚侠1 小时前
2025最新 SpringCloud 教程,从单体到集群架构,笔记02
笔记·spring cloud·架构
d***81721 小时前
解决SpringBoot项目启动错误:找不到或无法加载主类
java·spring boot·后端