我有一个学生问题:
我想就多核中的可见性问题提供建议和解释(如果有的话。
我在SpringBoot应用程序中使用注册表模式将不同的扫描程序实例映射到它们的名称。
配置:
@Bean
public WebScannerExecutor webScannerExecutor(final WebScannerClientProcessor webScannerClientProcessor) {
return new WebScannerExecutor(webScannerClientProcessor);
}
@Bean
public TLSScannerExecutor tlsScannerExecutor(final @Value("${tls.scanner.path}") String path, final BashProcessor bashProcessor) {
return new TLSScannerExecutor(path, bashProcessor);
}
@Bean
public ScanExecuterRegistry executerRegistry(final WebScannerExecutor webScannerExecutor, final TLSScannerExecutor tlsScannerExecutor) {
final ScanExecuter[] arr = new ScanExecuter[] {webScannerExecutor, tlsScannerExecutor};
return new ScanExecuterRegistry(arr);
}
注册表:
public class ScanExecuterRegistry {
private final ImmutableMap<ScannerType, ScanExecuter> registry;
public ScanExecuterRegistry(final ScanExecuter... executors) {
this.registry = ImmutableMap.<ScannerType, ScanExecuter> builder().putAll(Arrays.asList(executors).stream().collect(Collectors.toMap(ScanExecuter::getType, e -> e))).build();
}
现在我正在使用Guava的ImmutableMap,我很确定没有问题。但是......
private final Map<ScannerType, ScanExecuter> registry;
如果我取代ImmutableMap只是最终地图(不可变参考但不是内容),是否会出现问题?在多核系统中使用线程缓存,可见性等问题(即使使用singeltons)?
编辑:
只要您不修改内容,一切都很好
我想解释一下。我对java内存模型不太满意。
我可以更改地图的内容,只在spring配置类中添加新的扫描程序。所以应用程序将在任何情况下重新启动。还有问题吗?
答案 0 :(得分:2)
为了确保在多线程环境中共享的变量不会导致错误,您需要确保:
如果您将ImmutableMap
替换为可变Map
(例如HashMap
),则在线程之间共享Map
之后,final
未被静音。 / p>
请注意,将变量定义为final
并不能确保其内容永远不会更改。对于对象,final
仅表示无法更改引用,但例如可以向Map
static
添加,删除或更改项目。
(*)注意:正如@bowmore所解释的那样,必须保证safe publication共享变量:
安全发布使所有在发布之前编写的值对所有观察发布对象的读者都可见
这可以通过以下方式完成:
volatile
初始值设定项初始化对象引用。final
字段中。synchronized
字段中。