Java多线程中应有意识控制共享范围与方式,将状态封装为类的私有属性并统一加锁;优先使用无状态/不可变对象;用ThreadLocal隔离线程副本;善用Concurrent包工具类封装同步细节。

在 Java 多线程编程中坚持面向对象原则、减少共享状态,核心不是“避免一切共享”,而是**有意识地控制共享的范围、时机与方式**。关键在于把“状态”视为对象的内在职责,而非散落在方法或全局变量中的副产物。
把可变状态封装进单个对象并加锁保护
共享变量本身不可怕,可怕的是多个线程通过不同路径随意读写它。面向对象的解法是:让状态成为某个类的私有属性,所有访问都走该类定义的公共方法,并用同一把锁(如 synchronized 或 ReentrantLock)统一协调。
- 例如计数器类
Counter只暴露addOne()和get()方法,value字段严格 private,且两个方法都同步 —— 这样就将“如何安全更新”这个逻辑封装在对象内部,调用方无需关心锁或原子性。 - 若涉及多个变量需保持一致(比如账户余额和交易流水号),它们必须由同一个锁保护,否则会出现中间不一致状态。
优先使用无状态或不可变对象
无状态对象(如只含静态工具方法的类)天然线程安全;不可变对象(final 字段 + 构造后不再修改)也无需同步,因为一旦创建就不能改,所有线程看到的都是同一份确定快照。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 常见做法:用
String、LocalDate、BigDecimal等不可变类型代替可变容器;自定义类时用final修饰字段,不提供 setter,构造器完成全部初始化。 - Servlet 实例通常被多个线程共用,因此设计成无状态(不保存请求间数据)是最稳妥的选择。
用线程局部变量(ThreadLocal)隔离状态
当每个线程需要自己的一份“副本”状态(如数据库连接、用户上下文、格式化器),又不想传参或全局共享时,ThreadLocal 是面向对象的优雅解法 —— 它让每个线程拥有独立的变量实例,逻辑上仍是“每个线程一个对象”,只是由框架托管生命周期。
立即学习“Java免费学习笔记(深入)”;
- 典型场景:Spring 的事务管理、日志 MDC、SimpleDateFormat 的复用(避免每次 new)。
- 注意及时清理(尤其在线程池中),防止内存泄漏。
用并发工具类替代手动同步
Java 并发包(java.util.concurrent)里的类本身就是面向对象设计的典范:它们把复杂的状态管理和同步逻辑封装在类内部,对外只暴露高阶语义接口。
- 比如
AtomicInteger封装了 CAS 操作细节,调用者只需incrementAndGet(),不用写 synchronized 块; -
ConcurrentHashMap内部按段加锁或使用 CAS,使用者获得线程安全的 Map 接口,完全不必操心底层锁粒度。


















