synchronized(this) 用法详解
基本概念
synchronized(this) 是 Java 中的一种同步机制,通过对当前对象实例加锁来保证线程安全。当一个线程进入被 synchronized(this) 修饰的代码块时,会获取当前对象的锁,其他线程必须等待该线程释放锁后才能进入。
基本语法
public class MyClass {
public void method() {
synchronized(this) {
// 需要同步保护的代码
// 同一时刻只有一个线程能执行这里的代码
}
}
}
使用场景详解
1. 实例变量的线程安全操作
public class Counter {
private int count = 0;
// 不安全的递增方法
public void unsafeIncrement() {
count++; // 非原子操作,可能出现竞态条件
}
// 安全的递增方法
public void safeIncrement() {
synchronized(this) {
count++;
}
}
// 获取当前计数值
public int getCount() {
synchronized(this) {
return count;
}
}
}
2. 复杂业务逻辑的原子性保证
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public boolean withdraw(double amount) {
synchronized(this) {
// 检查余额是否充足
if (balance >= amount) {
// 模拟处理时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
balance -= amount;
return true;
}
return false;
}
}
public void deposit(double amount) {
synchronized(this) {
// 模拟处理时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
balance += amount;
}
}
public double getBalance() {
synchronized(this) {
return balance;
}
}
}
3. 多步骤操作的原子性保证
public class InventoryManager {
private Map<String, Integer> inventory = new HashMap<>();
public InventoryManager() {
// 初始化库存
inventory.put("item1", 100);
inventory.put("item2", 50);
}
// 批量扣减库存 - 需要保证原子性
public boolean deductInventory(Map<String, Integer> itemsToDeduct) {
synchronized(this) {
// 第一步:检查所有商品库存是否充足
for (Map.Entry<String, Integer> entry : itemsToDeduct.entrySet()) {
String itemId = entry.getKey();
Integer quantity = entry.getValue();
Integer currentStock = inventory.get(itemId);
if (currentStock == null || currentStock < quantity) {
return false; // 库存不足,整个操作失败
}
}
// 第二步:扣减所有商品库存
for (Map.Entry<String, Integer> entry : itemsToDeduct.entrySet()) {
String itemId = entry.getKey();
Integer quantity = entry.getValue();
Integer currentStock = inventory.get(itemId);
inventory.put(itemId, currentStock - quantity);
}
return true;
}
}
public int getStock(String itemId) {
synchronized(this) {
return inventory.getOrDefault(itemId, 0);
}
}
}
4. 缓存更新的线程安全
public class CachedDataService {
private Map<String, Object> cache = new HashMap<>();
private long lastUpdateTime = 0;
private static final long CACHE_TIMEOUT = 60000; // 1分钟
public Object getData(String key) {
synchronized(this) {
// 检查缓存是否过期
if (System.currentTimeMillis() - lastUpdateTime > CACHE_TIMEOUT) {
refreshCache();
}
return cache.get(key);
}
}
public void putData(String key, Object data) {
synchronized(this) {
cache.put(key, data);
lastUpdateTime = System.currentTimeMillis();
}
}
private void refreshCache() {
// 刷新缓存逻辑
cache.clear();
// 重新加载数据...
lastUpdateTime = System.currentTimeMillis();
}
public void clearCache() {
synchronized(this) {
cache.clear();
lastUpdateTime = 0;
}
}
}
与其他同步方式的比较
1. synchronized 方法 vs synchronized(this)
public class ComparisonExample {
private int value = 0;
// 方式1:同步整个方法
public synchronized void method1() {
value++;
// 其他操作...
}
// 方式2:同步代码块
public void method2() {
// 一些不需要同步的操作
System.out.println("不需要同步的操作");
synchronized(this) {
value++;
// 需要同步的操作
}
// 更多不需要同步的操作
System.out.println("更多不需要同步的操作");
}
}
2. synchronized(this) vs synchronized(object)
public class LockGranularityExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private int counter1 = 0;
private int counter2 = 0;
// 粗粒度锁定 - 锁定整个对象
public void coarseGrainedOperation() {
synchronized(this) {
counter1++;
counter2++;
}
}
// 细粒度锁定 - 分别锁定不同的资源
public void fineGrainedOperation() {
synchronized(lock1) {
counter1++;
}
synchronized(lock2) {
counter2++;
}
}
}
实际应用场景
1. 单例模式中的懒加载
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized(LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
2. 生产者-消费者模式
public class Buffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 10;
public void produce(int item) throws InterruptedException {
synchronized(this) {
while (queue.size() == capacity) {
// 缓冲区满,等待消费者消费
wait();
}
queue.offer(item);
System.out.println("生产: " + item);
notifyAll(); // 通知等待的消费者
}
}
public int consume() throws InterruptedException {
synchronized(this) {
while (queue.isEmpty()) {
// 缓冲区空,等待生产者生产
wait();
}
int item = queue.poll();
System.out.println("消费: " + item);
notifyAll(); // 通知等待的生产者
return item;
}
}
}
3. 状态机的状态转换
public class StateMachine {
private enum State {
IDLE, PROCESSING, COMPLETED, ERROR
}
private State currentState = State.IDLE;
public void startProcessing() {
synchronized(this) {
if (currentState == State.IDLE) {
currentState = State.PROCESSING;
System.out.println("开始处理...");
} else {
throw new IllegalStateException("不能从 " + currentState + " 状态开始处理");
}
}
}
public void completeProcessing() {
synchronized(this) {
if (currentState == State.PROCESSING) {
currentState = State.COMPLETED;
System.out.println("处理完成");
} else {
throw new IllegalStateException("不能在 " + currentState + " 状态完成处理");
}
}
}
public State getCurrentState() {
synchronized(this) {
return currentState;
}
}
}
注意事项和最佳实践
1. 避免死锁
public class DeadlockAvoidance {
private final Object lockA = new Object();
private final Object lockB = new Object();
// 错误的做法 - 可能导致死锁
public void badMethod1() {
synchronized(lockA) {
synchronized(lockB) {
// 操作...
}
}
}
public void badMethod2() {
synchronized(lockB) {
synchronized(lockA) {
// 操作...
}
}
}
// 正确的做法 - 统一加锁顺序
public void goodMethod1() {
synchronized(lockA) {
synchronized(lockB) {
// 操作...
}
}
}
public void goodMethod2() {
synchronized(lockA) { // 保持相同的加锁顺序
synchronized(lockB) {
// 操作...
}
}
}
}
2. 减少锁的持有时间
public class LockHoldingOptimization {
private List<String> dataList = new ArrayList<>();
// 不好的做法 - 锁持有时间过长
public void badPractice() {
synchronized(this) {
// 执行耗时操作
expensiveOperation();
// 添加数据
dataList.add("data");
}
}
// 好的做法 - 减少锁持有时间
public void goodPractice() {
// 先执行耗时操作
String result = expensiveOperation();
// 只在必要时加锁
synchronized(this) {
dataList.add(result);
}
}
private String expensiveOperation() {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "processed_data";
}
}
总结
synchronized(this) 的主要特点和使用建议:
适用场景:
保护实例变量的并发访问
保证多步骤操作的原子性
实现简单的线程同步
注意事项:
锁的是当前对象实例,同一类的不同实例之间不会互斥
可能影响性能,应尽量减少锁的持有时间
注意避免死锁
替代方案:
对于更复杂的并发控制,可以考虑使用 java.util.concurrent 包中的工具类
对于读多写少的场景,可以考虑使用 ReentrantReadWriteLock
对于无锁编程,可以考虑使用 Atomic 类
synchronized(this) 是 Java 中最基础也是最重要的同步机制之一,正确使用能够有效解决大部分线程安全问题。

浙公网安备 33010602011771号