假设我有以下课程:
@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;
}
}
假设:
(某些方法,例如visited
和markNodeVisited
已被遗漏)。我的问题是:
修改此类以使我的calculateNodeSum方法是线程安全的最佳方法(在性能方面)是什么?我能想到几个:
private final Object lock = new Object();
字段,并使用此锁定对象同步calculateNodeSum方法。使用类成员字段private Set<Node> visitedNodes
跟踪受访节点。这也需要我们在每次调用方法时清除visitedNodes
我们的跟踪。visitedNodes
类型Set<Node>
的{{1}}局部变量来跟踪访问过的节点@Scope
注释来管理范围(request
范围可能有效,只要每个请求调用此方法没有多个线程)答案 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;没有意义。