Java: проблема синхронизации данных

#java #volatile #data-synchronization

Вопрос:

Моя Java-программа запрашивает API клиента, и API клиента возвращает пару ключ-значение через нерегулярные промежутки времени (т. Е. не каждые 5 секунд / 10 секунд, иногда 1 секунду или 5 секунд).

И я вставил свой собственный код , который является a HashMap , в код API клиента для хранения всех пар ключ-значение.

Моя цель-запустить приведенный ниже код с пометкой»!!!», как только будут выполнены условия хэш-карты. Я не эксперт в синхронизации данных Java. Обратите внимание, что Thread.Sleep(3000) это не сработает, так как пары ключ-значение обновляются с нерегулярными интервалами времени. Более того, значение одного и того же ключа также будет меняться с течением времени. Я попробовал запустить программу ниже, и она сразу же пробежала блок кода, помеченный»!!!», чего я не хочу достичь.

Каково наиболее эффективное решение этой проблемы ?

 Class Testing{
    public static void main(String[] args){
        // connect to API...
        ClientAPI clientAPI = new ClientAPI();
        clientAPI.connect();

        // make a request to retrieve an update of a HashMap
        clientAPI.requestHashMapUpdate();

        // !!! execute the following block of code only if hashmap contains a specific key value pair, i.e. key1, 1 
        // if hashmap does not contain key or the key-value pair do not match , then wait until the key-value pair are matched and run the code
        if(clientAPI.getMyHashMap().containsKey("key1")){
            if(clientAPI.getMyHashMap().get("key1") == 1){
                    System.out.println("Print Me only if key and value are matched !!!!!!!!");
            }
        }

    }
}


Class ClientAPI{
    private HashMap<String,Integer> myHashMap;
    
    // Constructor
    public clientAPI(){
            myHashMap = new HashMap<String,Integer>();
    }

    // callback function of API's requestHashMapUpdate method
    public void updateHashMapKeyValuePair(String key, int value){
        System.out.println("Key:"   key   ", Value: "   value);
        // code i wrote to update hashmap with key value pair returned from API
        myHashMap.put(key,value);
    }

    // my code to retrieve the latest snapshot of myHashMap
    public HashMap<String,Integer> getMyHashMap(){
        return myHashMap;
    }

}
 

Комментарии:

1. На самом деле вы мало что можете сделать, кроме как проверять содержимое хэш-карты каждый раз, когда она обновляется. Если вы не можете получать уведомления о его обновлении, на самом деле вы мало что можете сделать, кроме опроса.

2. Есть ли способ уведомить программу о том, когда хэш-карта обновляется?

3. Не по своей сути. Просто уведомьте клиентов из кода, в котором вы обновляете карту.

Ответ №1:

Переопределите свой клиентский API (если он не закрыт для расширения):

 class MyClientAPI extends ClientAPI {
    ...
    @Override
    public void updateHashMapKeyValuePair(String key, int value) {
        super.updateHashMapKeyValuePair(key, value);
        if("key1".equals(key) amp;amp; 1 == value)
            System.out.println("Print Me only if key and value are matched !!!!!!!!");
    }
    ...
}
 

и просто проверяйте каждое новое поступающее значение.

Чтобы использовать его, только измените

 ClientAPI clientAPI = new MyClientAPI();
 

Другой способ решить эту проблему-предоставить вашему ClientAPI классу возможность регистрировать слушателей

 interface UpdateHashMapKeyValuePairListener {
    void digestUpdate(String key, int value);
}

class ClientAPI {
    ...
    private List<UpdateHashMapKeyValuePairListener> listeners = new ArrayList();
    ...
    public void registerUpdateListener(UpdateHashMapKeyValuePairListener u) {
        listeners.add(u);
    }
    ...
    public void updateHashMapKeyValuePair(final String key, final int value) {
        listeners.forEach(u -> u.digestUpdate(key, value));
        ...
    }
    ...
}
 

затем любой, кто хочет знать, когда вводится новое значение, просто реализует этот интерфейс, например

 ...
clientAPI.registerUpdateListener((key, value) -> {
    if("key1".equals(key) amp;amp; 1 == value)
        System.out.println("Print Me only if key and value are matched !!!!!!!!");
});
clientAPI.connect();
...
 

Ответ №2:

Проверяйте содержимое хэш-карты каждый раз, когда она обновляется. Для достижения этой цели вы можете зарегистрировать прослушиватель в Testing классе, который будет запускаться каждый раз HashMap , когда он обновляется в ClientAPI классе.

Сначала определите функциональный интерфейс для слушателя:

  @FunctionalInterface
  public interface OnUpdateMapListener {
      void onUpdateMap(Map<String, Integer> map);
  }
 

затем добавьте слушателя в ClientAPI

  public class ClientAPI {
        private HashMap<String, Integer> myHashMap;
        private OnUpdateMapListener onUpdateMapListener;
 

Определите onMapUpdate метод для передачи тела слушателя в ClientAPI :

 public void onMapUpdate(OnUpdateMapListener onUpdateMapListener) {
        this.onUpdateMapListener = onUpdateMapListener;
}
 

и вызвать прослушиватель при обновлении хэш-карты в updateHashMapKeyValuePair

 public void updateHashMapKeyValuePair(String key, int value) {
  System.out.println("Key:"   key   ", Value: "   value);
  // code i wrote to update hashmap with key value pair returned from API
   myHashMap.put(key, value);
   onUpdateMapListener.onUpdateMap(myHashMap);
 }
 

В основном методе зарегистрируйте слушателя и проверьте содержимое карты. Это будет срабатывать каждый раз ClientAPI , когда метод получает новое содержимое карты updateHashMapKeyValuePair :

 clientAPI.onMapUpdate(stringIntegerHashMap -> {
      // !!! the following code is executed every time the hashMap is updated
       if (clientAPI.getMyHashMap().containsKey("key1")) {
           if (clientAPI.getMyHashMap().get("key1") == 1) {
             System.out.println("Print Me only if key and value are matched !!!!!!!!");
           }
      }
});
 

ClientAPI класс:

 public class ClientAPI {
    private HashMap<String, Integer> myHashMap;

    private OnUpdateMapListener onUpdateMapListener;

    // Constructor
    public ClientAPI() {
        myHashMap = new HashMap<String, Integer>();
    }

    // callback function of API's requestHashMapUpdate method
    public void updateHashMapKeyValuePair(String key, int value) {
        System.out.println("Key:"   key   ", Value: "   value);
        // code i wrote to update hashmap with key value pair returned from API
        myHashMap.put(key, value);
        onUpdateMapListener.onUpdateMap(myHashMap);
    }

    // my code to retrieve the latest snapshot of myHashMap
    public HashMap<String, Integer> getMyHashMap() {
        return myHashMap;
    }

    public void requestHashMapUpdate() {
      //.....
    }

    public void onMapUpdate(OnUpdateMapListener onUpdateMapListener) {
        this.onUpdateMapListener = onUpdateMapListener;
    }
}
 

Testing класс:

  public static void main(String[] args) {
      // connect to API...
        ClientAPI clientAPI = new ClientAPI();
        clientAPI.connect();

        // make a request to retrieve an update of a HashMap
       clientAPI.requestHashMapUpdate();

        clientAPI.onMapUpdate(stringIntegerHashMap -> {
            // !!! the following code is executed every time the hashMap is updated
            if (clientAPI.getMyHashMap().containsKey("key1")) {
                if (clientAPI.getMyHashMap().get("key1") == 1) {
                    System.out.println("Print Me only if key and value are matched !!!!!!!!");
                }
            }
        });

        clientAPI.updateHashMapKeyValuePair("key1", 1);
        clientAPI.updateHashMapKeyValuePair("key1", 2);
    }
 

Результаты:

 Key:key1, Value: 1
Print Me only if key and value are matched !!!!!!!!
Key:key1, Value: 2