Search code examples
javavolatiledata-synchronization

Java: data synchronization issue


My Java program makes a request to client's API and client's API will return a key-value pair on irregular time intervals (i.e. not every 5 seconds / 10 seconds, sometimes 1 second or 5 seconds).

And I have inserted my own code which is a HashMap, into the client API code to store all the key-value pairs.

My goal is run the below code marked with "!!!" as soon as the Hashmap conditions are matched. I am not an expert in Java data synchronization. Note that Thread.Sleep(3000) would not work, as the key-value pairs are updated on irregular time intervals. Moreover, the value of the same key will also change over time. I tried the run the program below and it immediately ran through the block of code marked with "!!!", which is not what I want to achieve.

What is the most efficient solution to tackle this problem ?

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;
    }

}

Solution

  • Override your client API (if it is not closed to extends):

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

    and simply check each new value that comes in.

    To use it, only change

    ClientAPI clientAPI = new MyClientAPI();
    

    Another way to solve this is to provide your ClientAPI class with the ability to register listeners

    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));
            ...
        }
        ...
    }
    

    then, anyone who wants to know when a new value enters, just implement this interface, e.g.

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