Мне нужно разобрать ответ после совершения 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
навсегда, пока программа не будет запущена. Возможно ли это сделать? Также, как вы видите, я делаю много вещей в моем конструкторе. Есть ли лучший способ сделать то же самое по сравнению с тем, что я делаю?
В целом карта addressToIdMapping
всегда будет иметь только одну запись для IP-адреса, в котором работает код. И я в порядке, если карта обновляется каждые 30 минут, если processToTcpMapping
.
вы можете использовать метод 'putIfAbsent' на' ConcurrentHashMap', см. [Doc] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#putIfAbsent-KV -) – wwajerowicz
@wwajerowicz Что здесь делает 'putIfAbsent'? – user1950349
он будет обновлять запись только в том случае, если она не существует, что означает, что запись будет для одного IP-адреса обновляться только один раз. – wwajerowicz