0

我们有以下代码要在 Java 中执行:

public void doSomething() {
    doSomeDBOperationForOrg();
    doOtherOperations();
}

void doSomeDBOperationForOrg() { 
    //should be executed only once per organization.
}

void doOtherOperations() {
    //should be executed only when the DB operation for the organization is done, and not before
}

该方法doSomething被多个组织下的多个用户同时调用。我们只需要为doSomeDBOperationForOrg每个组织执行一次方法,并且doOtherOperations对于调用该doSomething方法的所有用户,但只有在doSomeDBOperationForOrg完成之后。

一种选择是通过doSomething和/或“同步” doSomeDBOperationForOrg,并维护更新组织的列表。

public synchronized void doSomething() {
    if(!orgUpdatedList.contains(organization)) {
        doSomeDBOperationForOrg();
        orgUpdatedList.add(organization);
    }
    
    doOtherOperations();
}

但这将阻止用户的所有线程,无论其组织如何。当我们拥有庞大的用户列表时,这是不可取的。有人可以建议一个更好的方法来实现这一目标吗?

4

1 回答 1

1

您想doOtherOperations();自由地并行执行,所以这不应该在任何(有效)synchronized块中。

但是您希望doSomeDBOperationForOrg();每个组织发生一次。当您处理多个线程时,像“每个 xyz 一次”这样的要求需要某种同步。

而且您不希望用户等待他们不属于的组织的初始化。

建议:

如果您有一个代表组织的类(我们称之为Organization)(从某种意义上说,一个组织被 1:1 映射到恰好一个实例,同一个组织没有重复的实例),那么您可以创建该类doSomeDBOperationForOrg();的同步实例方法Organization,并让此方法检查是否需要初始化。然后doSomething()很简单:

public void doSomething() {
    organization.doSomeDBOperationForOrg();
    doOtherOperations();
}

或者,更接近您当前的结构:

public void doSomething() {
    synchronized (organization) {
        if(!orgUpdatedList.contains(organization)) {
            doSomeDBOperationForOrg();
            orgUpdatedList.add(organization);
        }
    }
    doOtherOperations();
}

但请确保您使用线程安全orgUpdatedList,例如通过环绕Collections.synchronizedXyz()它!

通过在组织上进行同步,您可以确保来自一个组织的用户可以相互阻止,以便进行有序的初始化,但不受其他组织的用户的影响。

如果你没有合适的Organization类(也不能介绍一个),而只有一个String,你可以在organization.intern(). 该方法具有所有具有相同内容的字符串导致相同实例的属性。这是一种黑客,但应该工作。

于 2020-11-27T11:56:01.843 回答