我必须在服务器上进行HTTP调用后解析响应。如果响应不成功,则尝试另一个服务器,否则解析成功响应并填充两个ConcurrentHashMap并跳出for循环。所有的服务器将以相同的格式提供相同的确切响应。如何在第一次调用Singleton的过程中只更新一次地图?
下面是我的单身类上的ProcConfig
构造函数在第一次调用,调用loadConfig()
方法来初始化一切,然后检查addressToIdMapping
地图是否有与否的一个条目。如果不存在,则抛出异常。之后它启动后台线程,每隔30分钟它会调用loadConfig()
方法更新addressToIdMapping
和processToTcpMapping
图。
public class ProcConfig {
private static final Splitter SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final Map<String, Short> addressToIdMapping = new ConcurrentHashMap<>();
private final Map<DatacenterEnum, List<String>> processToTcpMapping = new ConcurrentHashMap<>();
private static class Holder {
private static final ProcConfig INSTANCE = new ProcConfig();
}
public static ProcConfig getInstance() {
return Holder.INSTANCE;
}
private ProcConfig() {
loadConfig();
checkArgument(!MapUtils.isEmpty(addressToIdMapping), "cannot find id, found '%s'.", addressToIdMapping);
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
loadConfig();
} catch (Exception ex) {
// log error
}
}
}, 60, 30, TimeUnit.MINUTES);
}
private void loadConfig() {
// current ipAddress where the program is running
Optional<String> ipAddress = Utils.getIPAddress();
List<String> servers = getServers();
for (String server : servers) {
try {
String response = HttpClient.getInstance().execute(makeUrl(server));
if (Strings.isNullOrEmpty(response) || response.equalsIgnoreCase("KEEP OUT")
|| response.equalsIgnoreCase("NOTHING FOUND")) {
continue;
}
parseConfig(response, ipAddress.get());
break;
} catch (Exception ex) {
// log error
}
}
}
private void parseConfig(final String response, final String ipAddress) throws IOException {
List<String> lines = IOUtils.readLines(new StringReader(response));
for (String line : lines) {
if (line.contains(ipAddress)) {
List<String> config = SPLITTER.splitToList(line);
Short id = Short.parseShort(config.get(2));
// this map will only have one entry for the ip address where it is running
addressToIdMapping.put(ipAddress, id);
} else if (line.contains("process_")) {
List<String> config = SPLITTER.splitToList(line);
String procAddr = config.get(0);
int datacenter = Integer.parseInt(config.get(1));
int portNumber = Integer.parseInt(config.get(3));
int numberOfPorts = Integer.parseInt(config.get(4));
DatacenterEnum colo = Utils.isProd() ? DatacenterEnum.name((byte) datacenter) : DatacenterEnum.DEV;
List<String> address = makeTcpAddress(procAddr, colo, portNumber, numberOfPorts);
processToTcpMapping.put(colo, address);
}
}
}
public Optional<Short> getId() {
Optional<String> ipAddress = Utils.getIPAddress();
return Optional.fromNullable(addressToIdMapping.get(ipAddress.get()));
}
}
现在我的问题是:我想在第一次调用单身期间只有一次更新我的addressToIdMapping
地图让getId()
方法总是返回地图中的第一个更新过程中有什么在那里。但是现在它会在每次更新30分钟后返回地图中的任何内容。例如:当第一次调用这个类时,它会更新地图,所以我想永远保持相同的值,直到程序运行。这可能吗?也正如你所看到的,我在我的构造函数中做了很多东西。与我正在做的事情相比,是否有更好的方法来做同样的事情?
一般来说addressToIdMapping
地图总是只有一个IP地址的条目在运行代码。而且我很好,如果processToTcpMapping
地图每30分钟更新一次。
你可以在'ConcurrentHashMap'上使用'putIfAbsent'方法参见[doc](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#putIfAbsent-KV - ) – wwajerowicz
@wwajerowicz'putIfAbsent'在这里需要做什么? – user1950349
它只会在条目不存在的情况下更新条目,这意味着只有一个IP地址的条目才会更新一次。 – wwajerowicz