什么是确保Spring组件中线程安全的最高效方法?

时间:2015-02-04 22:52:48

标签: java multithreading spring

假设我有以下课程:

@Component
public class MyComponent {

    public Double calculateNodeSum(Node node) {
        Double sum = node.getAmount();
        for (Node child : node.getChildren()) {
            if (!visited(child)) {
                markNodeVisited(child);
                sum += calculateNodeSum(child);
            }
        }
        return sum;
    }
}

假设:

  • 假设在进行任何这些计算时未修改节点图。

(某些方法,例如visitedmarkNodeVisited已被遗漏)。我的问题是: 修改此类以使我的calculateNodeSum方法是线程安全的最佳方法(在性能方面)是什么?我能想到几个:

  1. 在类中添加private final Object lock = new Object();字段,并使用此锁定对象同步calculateNodeSum方法。使用类成员字段private Set<Node> visitedNodes跟踪受访节点。这也需要我们在每次调用方法时清除visitedNodes我们的跟踪。
  2. 修改calculateNodeSum方法,以便我们最初创建,然后传递visitedNodes类型Set<Node>的{​​{1}}局部变量来跟踪访问过的节点
  3. 使用Spring的@Scope注释来管理范围(request范围可能有效,只要每个请求调用此方法没有多个线程)
  4. 我还没有想到的其他解决方案

2 个答案:

答案 0 :(得分:3)

最好的方法是不要在@Component中保留任何状态,因此不需要锁定。所以state只保存在局部变量中,这些变量作为参数传递给其他方法。所以,我想我会选择2。

答案 1 :(得分:0)

问题的核心是线程安全的意思。

  

通过线程安全,我的意思是我不希望我的受访节点集被破坏。

我理解。但是,给定的代码不会改变图形。 (好的...... markNodeVisited(child)可能会......但是如果确实如此,那么你的算法本质上是不可重入的,这会产生以下影响......)

  

示例:MyComponent被实例化为单例bean(Spring默认值)。我有两个线程A和B.线程A调用具有十亿个节点的树结构的calculateNodeSum。几分之一秒后,线程B使用节点的子集调用calculateNodeSum,使得线程A和线程B中的节点重叠。我希望在每个线程上正确计算总和。如果没有一些安全的策略,我的访问节点列表将由两个线程写入。

显然,如果你想同时进行遍历,markNodeVisited必须记录&#34;标记&#34;以每种遍历使用独立标记集的方式。这是给定的。

这里是获得准确&#34;的问题。计数。

  • 如果图表正在变异,那么只有阻止突变或(有效)快照图表,才能获得即时准确的总和。显然,吸气剂需要同步等,以避免在遍历期间或之前发生突变导致的记忆异常。

  • 如果图形没有被变异,那么它只是以线程安全的方式读取节点信息。使相关的getter同步应该足够了。

总结 - 除非您明确指出预期的(非线程)行为,线程正在做什么,除非您提供其余的代码,否则我们无法真正给您答案关于如何使代码线程安全。


线程安全性是根据正确性来定义的。基本上,这意味着只有一个线程时正确的代码在有多个线程时也是正确的。这一切都取决于你的意思是正确的。如果你没有说明&#34;更正&#34;意味着,&#34;线程安全&#34;没有意义。