Как ждать обновления кэша данных, не влияя на другие вызовы кэша - PullRequest
0 голосов
/ 06 ноября 2019

У меня есть центральный кеш данных, который обновляется несколькими потоками, выполняющими запросы к базе данных SQL. Существует также механизм, который проверяет, когда последний каждый конкретный элемент (Mydata) в кэше данных был извлечен, и закрывает соответствующий поток, если достигнут определенный порог времени (т. Е. Если данные не были получены в последнем30 минут). Этот механизм используется для того, чтобы попытаться уменьшить спрос на базу данных и минимизировать длительные запросы.

Существует также ряд потоков, получающих данные из кэша, и, следовательно, проблема в том, что хотя определенный элемент (Mydata) не обновляется, он может быть запрошен потоком в какой-то момент,Когда это происходит, есть проверка, работает ли соответствующий поток, а если нет, он запускается снова, как показано ниже ...

private static HashMap<String, MyData> dataMap = new HashMap<>(10);

public static MyData getMyData(String identifier) {
  if(!MyThreadManager.getInstance().isRunning(identifier)) {
     LOG.info("Thread with identifier={} possibly stopped, restarting.", identifier);
     MyThreadManager.getInstance().startThread(identifier);
  }
  MyData myData= null;
  if(dataMap.containsKey(identifier)) {
     myData= dataMap.get(identifier);
  } else {
     LOG.debug("No data found in dataMap for identifier={}, thread possibly terminated. Restarting.", identifier);
  }
  return myData;
}

... сам механизм работает нормально, но ярискуйте тем, что при запуске dataMap.get(identifier) он все еще может содержать только «устаревшую» версию myData (поскольку перезапущенный поток все еще может обрабатывать). Однако я хочу гарантировать, что возвращаемые данные уже были обновлены. Чтобы сделать это, я мог бы добавить таймер сна после перезапуска потока на секунду, что должно быть достаточно времени, чтобы поток обновил свои данные в dataMap до запуска dataMap.get(identifier).

if(!MyThreadManager.getInstance().isRunning(identifier)) {
  LOG.info("Thread with identifier={} possibly stopped, restarting.", identifier);
  MyThreadManager.getInstance().startThread(identifier);
  try {
        Thread.sleep(1000L);
    } catch (Exception e) {
        LOG.error(e.getMessage());
    }
}

Большая проблема, с которой я столкнулся в этой реализации, заключается в том, что она может негативно повлиять на любые другие потоки, пытающиеся получить информацию.

Вопрос. Как реализовать поточно-неблокируемый способ «ожидания» обновления кэша в случае перезапуска потока без влияния на другие потоки, использующие тот же кеш данных.

1 Ответ

0 голосов
/ 06 ноября 2019

Хорошо, так что провели несколько тестов. Если метод getMyData вызывается из потока ...

public class MyRunnable implements Runnable {

  private String identifier = "";

  public MyRunnable(String identifier) {
    this.identifier = identifier;
  }

  @Override
  public void run() {
    MyData myData = MyDataManager.getInstance().getMyData(identifier)
    System.out.println(String.format("Data retrieved : %s", myData.toString()));
  }

}

..., то введение Thread.sleep(1000L); для перезапуска потока сбора данных не повлияет на другие параллельные потоки. Если, конечно, не добавляется ключевое слово метода synchronized, что заставляет по одному избегать условий гонки.

Поскольку эти запросы в конечном итоге исходят из запросов HTTP, обрабатываемых сервлетомконтейнер, выше, будет работать нормально. Как сервлеты позволяют JVM обрабатывать каждый запрос в отдельном потоке Java. Таким образом, каждый вызов метода getMyData происходит в своем собственном потоке, и любое «ожидание» будет влиять на другие запросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...