缺陷 & 规避

  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() {
     }
 }
相关推荐
CXDNW9 分钟前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙10 分钟前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
IT技术分享社区19 分钟前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
极客代码22 分钟前
【Python TensorFlow】入门到精通
开发语言·人工智能·python·深度学习·tensorflow
ssf-yasuo23 分钟前
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
论文阅读·笔记·prompt
天行健PLUS28 分钟前
【经验分享】六西格玛管理培训适合哪些人参加?
经验分享
疯一样的码农29 分钟前
Python 正则表达式(RegEx)
开发语言·python·正则表达式
代码之光_198030 分钟前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi35 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
&岁月不待人&1 小时前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin