如何解决对单例类方法的并发调用产生不一致的结果
我有一个单例类,该类具有一个从目录读取所有文件的方法。传入configRootDir
和ContentType
(用于类型引用的Enum)。readAllConfigsFromLocaldisk
方法列出目录中的所有文件,并逐一处理以将文件内容映射到预期的对象类型到ContentType
参数。
// Config type reference
public enum ConfigType {
MY_TYPE,MY_OTHER_TYPE
}
// Singleton class
public class Singleton {
private static Singleton instance;
private Map<String,MyType> myTypeMap = new HashMap();
private Map<String,MyOtherType> myOtherTypeMap = new HashMap();
private Singleton() {}
public synchronized static Singleton getSingleton() {
if (istance == null)
istance = new Singleton();
return istance;
}
public Map<String,MyType> getMyTypeMap(String filePath,ConfigType configType,String filePattern){
myTypeMap.clear();
readAllConfigsFromLocaldisk(configRootDir,configType,filePattern);
return myTypeMap;
}
public Map<String,MyOtherType> getMyOtherTypeMap(String filePath,String filePattern){
myOtherTypeMap.clear();
readAllConfigsFromLocaldisk(configRootDir,filePattern);
return myOtherTypeMap;
}
/**
* Get all files in config root directory and parse one by one
* @param configRootDir Root directory for configurations
* @param configType Configuration type
* @param filePattern File pattern
*/
private void readAllConfigsFromLocaldisk(String configRootDir,String filePattern) {
try (Stream<Path> walk = Files.walk(Paths.get(configRootDir))) {
Pattern pattern = Pattern.compile(filePattern);
List<Path> filePaths = getLocalFilePaths(walk,pattern);
if (!filePaths.isEmpty()) {
for (Path filePath : filePaths) {
String relativePath = filePath.toString();
parseConfigFile(relativePath,configType);
}
}
} catch (IOException ex) {
logger.error("Specified config root directory not found.",ex);
}
}
/**
* Read a given configuration file from local disk and map to specified config type
*
* @param configFile Relative path to config file on local disk
* @param configType Configuration type (MY_TYPE or MY_OTHER_TYPE)
*/
private void parseConfigFile(String filePath,ConfigType configType ){
String configContent = Files.readString(Paths.get(filePath),Charsets.UTF_8);
// Parse based on config type and overwrite map
switch (configType) {
case MY_TYPE:
MyTypeConf myTypeConf = Core.getMapper().readValue(configContent,MyTypeConf.class);
List<MyType> myTypeRefs = myTypeConf.getMyTypeList();
myTypeMap.putAll(myTypeRefs.stream().collect(Collectors.toMap(MyType::getId,Function.identity())));
case MY_OTHER_TYPE:
MyOtherTypeConf myOtherTypeConf = Core.getMapper().readValue(configContent,MyOtherTypeConf.class);
List<MyOtherType> myOtherTypeRefs = myOtherTypeConf.getMyOtherTypeList();
myOtherTypeMap.putAll(myOtherTypeRefs.stream().collect(Collectors.toMap(MyOtherType::getId,Function.identity())));
}
}
/**
* Get file paths of all matching files exist in configured streaming directory and sub folders from disk.
*
* @param walk Stream of paths in config root directory.
* @param pattern Pattern to math when discovering files.
* @return List of Path objects for all files matching the pattern.
*/
private List<Path> getLocalFilePaths(Stream<Path> walk,Pattern pattern) {
return walk.filter(Files::isRegularFile).filter(p -> {
String fileName = p.getFileName().toString();
Matcher matcher = pattern.matcher(fileName);
return matcher.matches();
}).collect(Collectors.toList());
}
}
一组Akka参与者同时调用了两个公共方法getMyTypeMap
和getMyOtherTypeMap
。在某些情况下将文件内容映射到对象时,我得到com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
。
似乎原因是试图将configContent
映射到MyType
时实际上是MyOtherType
可解析的,反之亦然。
我看了其他几个地方,但无法完整了解它。我试图了解同时调用readFile
时发生的情况以及为什么混淆文件内容。有人可以帮助我了解这一点吗?预先感谢。
解决方法
您已经声明了两个 shared 变量:
private Map<String,MyType> myTypeMap = new HashMap();
private Map<String,MyOtherType> myOtherTypeMap = new HashMap();
由于HashMap
不是线程安全的,所以当多个线程同时访问它的一个实例(并且至少有一个线程正在修改它)时,可能会发生最奇怪的事情。
使用线程安全映射无法解决语义问题,因为getMyTypeMap
的所有调用都返回相同的映射实例并对其进行操作,因此调用者无法像其他仍在执行{{ 1}}(再次)对其进行更改。 getMyTypeMap
的并发调用也是如此。
由于每种方法均以getMyOtherTypeMap
调用开头,因此似乎不希望在该方法的不同调用之间共享数据,因此,这些方法不应共享数据。
看来,您遇到的主要障碍是如何重用代码以获取不同的结果类型。请勿使用该clear()
类型:
enum
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。