在第一次致电Singleton期间如何更新地图一次? [英] How to update map only once during the first call to Singleton?

查看:213
本文介绍了在第一次致电Singleton期间如何更新地图一次?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在服务器上进行HTTP调用后,我必须解析一个响应。如果响应不成功,请尝试另一台服务器,否则解析成功的响应,并填充两个ConcurrentHashMap并突破for循环。所有的服务器将以相同的格式给出相同的确切响应。

I have to parse a response after making HTTP call on the server. If the response is not successful then try another server otherwise parse the successful response and populate two ConcurrentHashMap and break out of for loop. And all the servers will give same exact response in the same format.

下面是我的单例类,它在第一次调用 ProcConfig的构造函数中,调用 loadConfig()方法初始化所有内容,然后检查是否 addressToIdMapping map有一个进入或不进入如果它不在那里它会抛出异常。之后,它启动一个后台线程,每30分钟会调用 loadConfig()方法来更新 addressToIdMapping processToTcpMapping map。

Below is my singleton class which on the first call in the constructor of ProcConfig, calls loadConfig() method to initialize everything and then check whether addressToIdMapping map has one entry in it or not. If it is not there then it throws exception. After that it starts a background thread where every 30 minutes it will call loadConfig() method to update addressToIdMapping and processToTcpMapping map.

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 映射中保持相同的值,直到程序运行。这可以做吗另外你可以看到我在构造函数中做了很多东西。有什么比我做的更好的方式做同样的事情吗?

Now my question is: I want to update my addressToIdMapping map only once during the first call to the singleton so that getId() method always return what was there during the first update in the map. But right now it will return whatever is there in the map after every update of 30 minutes. For example: when the first time this class is called, it will update the map so I want to keep the same value in addressToIdMapping map forever till the program is running. Is this possible to do? Also as you can see I am doing lot of stuffs in my constructor. Is there any better way to do same thing as compared to I am doing?

一般来说, addressToIdMapping map将永远在代码运行的IP地址中只有一个条目。如果 processToTcpMapping 地图每30分钟更新一次,我很好。

In general addressToIdMapping map will always have only one entry for the IP Address where the code is running in. And I am fine if processToTcpMapping map getting updated every 30 minutes.

推荐答案

你可以使用 putIfAbsent 方法在 ConcurrentHashMap 文档

只有当条目不存在时,才会更新条目,这意味着一个IP地址的条目只能更新一次。

It will only update the entry if it doesn't exists, which means that entry for one IP address will only get updated once.

这篇关于在第一次致电Singleton期间如何更新地图一次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆