[英]Is thread safety an issue here?
上下文:我有一个服务 class 有一个公共foo
方法(将从 rest 控制器调用),这反过来将调用私有fooHelper
传递一个列表fooHelper
后填充的其他私有方法调用。 这样做的原因是我想保持foo
方法的简短(请建议我创建私有fooHelper
的方法是否错误)。
问题:线程安全可能是这里的一个问题吗? 如果多个线程同时访问foo
方法(参考传递的列表对象)? 我知道我可以使用不可修改列表,但我的问题是特定于当前方法是否存在线程安全问题的场景?
我用谷歌搜索并阅读了几篇文章,根据他们的说法,这应该不是问题,因为foo
正在创建new List
,因此没有线程将共享相同的列表。 我的理解正确吗?
任何帮助将不胜感激,如果我无法清楚地提出我的问题,也请原谅。 欢迎任何编辑或建议。
@RequiredArgsConstructor
@Service
public class A {
@Override
public List<RoundUpResponse> foo(String token) {
final List<RoundUpResponse> roundUpResponseList = new ArrayList<>();
final Accounts accounts = getAccounts(token);
final List<Account> accountList = accounts.getAccounts();
accountList.forEach(account -> fooHelper(token, roundUpResponseList, account));
return roundUpResponseList;
}
private void fooHelper(String token, List<RoundUpResponse> roundUpResponseList, Account account) {
final FeedItems transactionFeed = getTransactionFeed(token, account); // private
final SavingsGoal savingsGoal = getSavingsGoal(token, account); // private
final Long spareChange = calculateSpareChange(transactionFeed, savingsGoal); // private
final SavingsGoalTopUp savingsGoalTopUpPayload = createTopUpPayload(account, // privatespareChange);
final String savingsGoalTransferId = topUpSavingsGoal(token, account, savingsGoal, savingsGoalTopUpPayload); // private
roundUpResponseList.add(roundUpResponseService.createResponsePerAccount(account, savingsGoal.getName(), savingsGoalTopUpPayload, savingsGoalTransferId)); // private
}
代码可能是线程安全的,也可能不是线程安全的,具体取决于getAccounts()
方法。 这些方法应该以线程安全的方式返回其对象底层结构的防御性副本。 然后你的代码将是线程安全的。 另一方面,如果,例如, accounts.getAccounts()
只是返回对内部帐户列表的引用,那么当您在foo
方法中迭代该列表时,另一个线程可能会动态修改该列表。 所以,确保getAccounts
是安全的,然后你的代码是好的。
更新
对 getAccounts() 有不同的调用堆栈与其线程安全无关。 这是一个非线程安全的实现:
class Accounts {
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
}
在这种情况下,每个调用线程都将获得对内部结构的相同引用,因此在您执行foo
方法之后
final List<Account> accountList = accounts.getAccounts();
在 thread1 中,一些 thread2 可以修改 accountList,它可以中断foo
中此列表的迭代。 您应该创建防御副本,例如:
class Accounts {
private List<Account> accounts;
public List<Account> getAccounts() {
synchronized(this) {
return new ArrayList<>(accounts);
}
}
}
注意synchronized
并返回对列表副本的引用,我们以希望线程安全的方式进行(“希望”,因为我们必须确保accounts
的所有修改也在同一个 object 上synchronized
)。
在您的实现中,您通过执行 REST API 调用来获取列表,该调用应该为每个调用返回一个新列表,独立于另一个。 所以你的实现是安全的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.