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 中最基础也是最重要的同步机制之一,正确使用能够有效解决大部分线程安全问题。

posted @ 2025-11-27 17:40  yub4by  阅读(4)  评论(0)    收藏  举报