---
globs: ["**/*.java"]
---

# 安全编码与并发规范

## 权限与数据安全
- 用户个人页面或功能必须进行权限控制校验，防止水平越权
- 用户敏感数据必须脱敏展示，如手机号 `139****1219`
- 用户请求的所有参数必须做有效性验证，防止：page size 过大导致 OOM、恶意 order by 慢查询、缓存击穿、SSRF、SQL 注入、Shell 注入、ReDoS
- 禁止向 HTML 页面输出未经安全过滤或转义的用户数据（防 XSS）
- 表单和 AJAX 提交必须执行 CSRF 安全验证
- URL 外部重定向必须执行白名单过滤
- 服务器内部重定向使用 forward，外部重定向使用 URL 统一代理模块生成

## 防刷与防重放
- 用户输入内容场景（发帖、评论、消息）必须实现防刷和违禁词过滤
- 使用平台资源（短信、邮件、电话、下单、支付）必须实现防重放：数量限制、疲劳度控制、验证码校验
- 文件上传必须严格检查文件大小和类型

## 线程池规范
- 线程资源必须通过线程池提供，禁止显式创建线程
- 禁止使用 `Executors` 创建线程池，必须使用 `ThreadPoolExecutor` 显式指定参数
  - `FixedThreadPool/SingleThreadPool`：队列长度 `Integer.MAX_VALUE`，可能 OOM
  - `CachedThreadPool`：线程数量 `Integer.MAX_VALUE`，可能 OOM
  - `ScheduledThreadPool`：队列长度 `Integer.MAX_VALUE`，可能 OOM
- 创建线程或线程池时必须指定有意义的线程名称，方便排查问题

## 并发控制
- 获取单例对象必须保证线程安全
- `SimpleDateFormat` 是线程不安全的，禁止定义为 static 变量；使用 `ThreadLocal` 包装或改用 `DateTimeFormatter`
- 必须回收自定义 `ThreadLocal` 变量，尤其在线程池场景，使用 `try-finally` 清理
- 高并发时优先使用无锁数据结构；能锁区块不锁方法体；能用对象锁不用类锁
- 对多个资源同时加锁时，保持一致的加锁顺序，避免死锁
- Lock 的 `lock()` 必须在 try 块之外调用，`unlock()` 放在 finally 块
- 使用 `tryLock()` 时，进入业务代码前必须判断是否持有锁
- 并发修改同一记录：冲突概率 < 20% 用乐观锁（version），否则用悲观锁；乐观锁重试不少于 3 次
- 资金相关敏感信息使用悲观锁：一锁二判三更新四释放
- 多线程定时任务使用 `ScheduledExecutorService`，禁止 `Timer`（一个任务异常会终止所有任务）
- 多线程使用 `Random` 时，使用 `ThreadLocalRandom`（JDK7+）避免竞争
- 双重检查锁延迟初始化必须声明目标属性为 `volatile`
- `volatile` 适用于一写多读场景；多写场景使用 `AtomicInteger` 或 `LongAdder`（JDK8+）
- 高并发场景禁止用"等于"作为中断条件，使用区间判断

## 异常处理规范
- 可预检查的 RuntimeException（NPE、IndexOutOfBoundsException）通过条件判断规避，禁止 catch
- 禁止用异常做流程控制或条件控制
- catch 时区分异常类型，禁止对大段代码笼统 try-catch
- 捕获异常必须处理，禁止空 catch；不处理则 throws 向上抛
- 事务场景中 catch 异常后如需回滚，必须手动回滚事务
- finally 块必须关闭资源对象和流对象（JDK7+ 使用 try-with-resources）
- 禁止在 finally 块中使用 return
- 捕获异常必须与抛出异常完全匹配或为其父类
- 调用 RPC、二方包、动态生成类时，使用 `Throwable` 捕获异常
- 自定义业务异常使用 `BusinessException/ServiceException`，禁止直接抛 `RuntimeException/Exception/Throwable`
- 防止 NPE 的关键场景：基本类型自动拆箱、数据库查询结果、集合元素、远程调用返回、Session 数据、级联调用

## 常见错误模式
- ❌ `Executors.newFixedThreadPool(10)` → ✅ `new ThreadPoolExecutor(coreSize, maxSize, keepAlive, unit, queue, factory)`
- ❌ `static SimpleDateFormat sdf = ...` → ✅ `ThreadLocal<DateFormat>` 或 `DateTimeFormatter`
- ❌ `try { lock.lock(); ... } finally { lock.unlock(); }` → ✅ `lock.lock(); try { ... } finally { lock.unlock(); }`
- ❌ `try { obj.method(); } catch (NullPointerException e) {}` → ✅ `if (obj != null) { obj.method(); }`
