同步基于值,而不是对象

2022-09-04 20:01:43

我想在Java中做这样的事情

  public void giveMoney(String userId, int money) {
    synchronized (userId) {

        Profile p = fetchProfileFromDB(userId);
        p.setMoney(p.getMoney() + userId);
        saveProfileToDB(p);

    }
   }

但是,当然,在字符串上进行同步是不正确的。做这样的事情的正确方法是什么?


答案 1

如果用户 ID 集受到限制,则可以在 的 暂存版本上进行同步。String

要么使用(有一些缺点)要么像番石榴Interners这样的东西,如果你需要对实习有更多的控制。String.intern()


答案 2

原则上,您可以在Java中的任何对象上进行同步。在对象上进行同步本身并不是“不正确的”;这取决于你到底在做什么。String

但是,如果是方法中的局部变量,那么这将不起作用。执行方法的每个线程都有自己的变量副本(可能引用每个线程的不同对象);当然,仅当在同一对象上同步多个线程时,线程之间的同步才有效。userIdString

您必须将要同步的对象放在包含块的方法的对象的成员变量上。如果多个线程随后在同一对象上调用该方法,则您将实现相互排他性。synchronized

class Something {
    private Object lock = new Object();

    public void someMethod() {
        synchronized (lock) {
            // ...
        }
    }
}

您还可以使用包中的显式锁,如果需要,它可以为您提供更多控制:java.util.concurrent.locks

class Something {
    private Lock lock = new ReentrantLock();

    public void someMethod() {
        lock.lock();
        try {
            // ...
        } finally {
            lock.unlock();
        }
    }
}

特别是如果你想要一个用于写入的独占锁,但你不希望线程在读取时必须等待彼此,你可能想要使用.ReadWriteLock


推荐