本文目录导读:

- 核心设计原则(先于代码)
- 标准同步处理流程(以
synchronized为例) - 使用
ReentrantLock的规范流程(更灵活的场景) - 关于“流程”的进阶规范:等待-通知模式 (Wait/Notify)
- 总结:规范同步流程的“清单”
- 例外情况处理
在Java中,规范处理同步(Synchronization)是保证多线程安全、避免死锁和性能瓶颈的核心,这里的“同步处理流程”通常指使用锁(如 synchronized、ReentrantLock)或原子类管理共享资源访问的模式。
下面我将从设计原则、标准编码流程、常见陷阱及规范几个方面为你拆解。
核心设计原则(先于代码)
在写同步代码前,先思考以下3点:
- 最小化锁的范围:只锁必要的代码块,不要锁整个方法(尤其是耗时操作)。
- 明确锁的对象:锁的是
this、类对象Class、还是某个专门的final锁对象?确保多个线程看到的是同一把锁。 - 避免死锁:如果存在多个锁,保证所有线程获取锁的顺序一致。
标准同步处理流程(以 synchronized 为例)
synchronized 是Java最基础的同步机制,流程最典型,规范写法如下:
明确共享资源(要保护的数据)
- 确定哪些变量/对象会被多个线程同时读写。
- 规范:将这些字段标记为
private,并添加final(如果引用不变)。
选择合适的锁对象
- 实例方法同步:锁是
this(当前实例),适合保护实例级别的状态。 - 静态方法同步:锁是
ClassName.class,适合保护类级别的状态。 - 代码块同步:最推荐,可以指定任意对象作为锁。
- 规范:锁对象应声明为
private final,防止外部访问或篡改。
- 规范:锁对象应声明为
编写同步代码块(核心流程)
标准模板:
public class Counter {
// 1. 共享资源(私有)
private int count = 0;
// 2. 创建一个私有的、最终的锁对象(推荐)
private final Object lock = new Object();
// 3. 所有需要同步访问共享资源的方法,都使用同一个lock
public void increment() {
synchronized (lock) { // 只锁关键操作
count++;
// 可以在这里添加复杂逻辑,但要保持块尽量小
} // 锁自动释放
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
对比错误写法:
// 错误:直接同步整个方法,并且锁的是this,可能被外部篡改
public synchronized void increment() {
// 如果这个方法里还有耗时操作(如IO),锁会占用很久,降低性能
count++;
// 还有一些数据库操作...
}
使用 ReentrantLock 的规范流程(更灵活的场景)
相比于 synchronized,ReentrantLock 支持超时、可中断、公平锁等,流程规范如下:
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class LockExample {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock(); // 非公平锁性能更好
public void safeIncrement() {
// 1. 获取锁(建议用try...finally保证释放)
lock.lock();
try {
count++; // 临界区
} finally {
lock.unlock(); // 2. 必须释放!即使发生异常
}
}
// 更健壮的写法:带超时,避免无限等待
public boolean tryIncrementWithTimeout() {
boolean acquired = false;
try {
// 尝试最多等待100ms获取锁
acquired = lock.tryLock(100, TimeUnit.MILLISECONDS);
if (acquired) {
count++;
return true;
} else {
// 获取锁失败,可以做其他事情或者返回错误
System.out.println("获取锁超时,执行降级逻辑");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
return false;
} finally {
if (acquired) {
lock.unlock(); // 只在获得锁时释放
}
}
}
}
流程”的进阶规范:等待-通知模式 (Wait/Notify)
当一个线程需要满足特定条件(如队列非空)才能继续执行时,规范的同步流程是在循环中等待:
public class BlockingQueue {
private final Object lock = new Object();
private final List<Object> queue = new LinkedList<>();
private final int capacity;
public void put(Object item) throws InterruptedException {
synchronized (lock) {
// 1. 必须用while,不能用if,防止虚假唤醒
while (queue.size() == capacity) {
lock.wait();
}
queue.add(item);
lock.notifyAll(); // 唤醒所有等待的线程
}
}
public Object take() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) { // 再次检查条件
lock.wait();
}
Object item = queue.remove(0);
lock.notifyAll();
return item;
}
}
}
规范要点:
- 必须在
synchronized块内调用wait()/notify()。 - 条件检查用
while而非if。
规范同步流程的“清单”
| 步骤 | 规范要求 | 反例 / 陷阱 |
|---|---|---|
| 识别临界区 | 仅保护会变的共享数据,不要锁方法内部的局部变量 | 锁了整个方法,包括不被共享的局部变量 |
| 选择锁对象 | 使用 private final Object lock 或 this / ClassName.class 并明确其范围 |
使用字符串常量或可能被修改的对象作为锁 |
| 获取锁 | 尽量缩小作用域(synchronized 块),减少锁持有时间 |
在同步块内进行磁盘IO、网络请求等耗时操作 |
| 访问共享资源 | 在临界区内完成所有复合操作(如 i++ 的读取+写入) | 在临界区外读取,临界区内写入(导致原子性破坏) |
| 释放锁 | ReentrantLock 必须放在 finally 块中释放 |
lock.lock() 后不写 finally { unlock() } |
| 多锁顺序 | 所有需要加多个锁的线程,按固定顺序加锁(如按A->B) | 线程1锁A再锁B,线程2锁B再锁A(死锁) |
| 条件等待 | 使用 while(condition) { wait() } 的模式 |
使用 if(condition) { wait() } |
| 优先使用高级工具 | 能用 ConcurrentHashMap、AtomicInteger、CopyOnWriteArrayList 等,就不要自己手写锁 |
“重复造轮子”,性能差且易出错 |
例外情况处理
- 线程中断:当你在同步块内调用
InterruptedException时,规范做法是Thread.currentThread().interrupt()恢复中断状态,而不是吞掉异常。 - 锁的可见性:
synchronized和Lock都保证了进入锁时刷新变量,退出锁时写回。如果不使用同步机制,普通变量可能永远看不到其他线程的修改。 - 异常处理:如果在临界区内抛出非受检异常(如
NullPointerException),“锁”会自动释放(synchronized)或需要在finally中释放(ReentrantLock),务必保证异常情况下锁也能释放。
最后建议:在编写你自己的同步逻辑之前,先看看java.util.concurrent包中是否有现成的工具(Semaphore、CountDownLatch、线程安全的集合等),很多时候,不需要自己手写复杂流程,用官方封装好的并发组件更安全、更高效。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播