You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java线程同步:为何需单独锁log而非仅用synchronized方法?

关于Account类同步方式的疑问:单独锁log是否必要?

问题背景

我实现了如下Java代码的Account类:

public class Account {
    private static List<Double> log = new ArrayList<Double>();
    private double balance;

    public Account(){balance = 0.0;}

    public synchronized void deposit(double val){
        balance = balance + val;
        log.add(val);
    }

    public synchronized void withdraw(double val){
        balance = balance - val;
        log.add(val);
    }
}

我认为这个同步方式是正确的,因为synchronized方法保证了对log的操作是原子性的,还通过如下测试验证:

Account a = new Account();
Thread t = new Thread(() -> a.deposit(30));
Thread j = new Thread(() -> a.withdraw(20));
t.start();
j.start();
sleep(300);
System.out.println(Account.getLog());

但后来看到另一种实现方案,在方法内部单独对log对象加锁执行add操作:

class Account {
    private static List<Double> log = new ArrayList<Double>();
    private double balance;

    public Account() {
        balance = 0.0;
    }

    public synchronized void deposit(double val) {
        balance = balance + val;
        synchronized (log) {
            log.add(val);
        }
    }

    public synchronized void withdraw(double val) {
        balance = balance - val;
        synchronized (log) {
            log.add(-val);
        }
    }
}

我产生了疑问:为何需要单独锁log,仅用同步方法是否足够?


解答

仅用synchronized方法的局限性

你的测试能正常运行,是因为只用到了一个Account实例——此时两个线程竞争的是同一个Account实例锁,自然不会同时操作log。但这种方案存在严重的线程安全隐患:

  • log是静态变量,属于Account类的共享资源,而非单个实例。如果程序中创建了多个Account实例,不同实例的synchronized方法持有的是各自的实例锁,彼此不互斥。比如线程1操作a1.deposit,线程2操作a2.withdraw,两个线程会同时进入同步方法,并行执行log.add,而ArrayList本身不是线程安全的,这会导致并发修改异常或者日志数据混乱。

单独锁log的必要性

单独对log对象加锁,本质是把锁的粒度和共享资源绑定:

  • 不管有多少个Account实例,所有线程操作log时都会竞争同一个锁(log对象本身),确保对log的所有修改都是串行执行的,从根本上保证了这个静态共享资源的线程安全,不受实例数量的影响。

额外补充

另外,原代码的withdraw方法中log.add(val)是错误的——取款应该记录负数金额,第二种方案的log.add(-val)才是正确的日志记录逻辑。


内容的提问来源于stack exchange,提问作者Luca Pedersoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:10:21