I have a below class in which I have a add
method which is called by another thread to populate my clientidToTimestampHolder
multimap. And then in the same below class, I start a background thread which runs every 60 seconds and calls a processData()
method which iterates the same map and send all those data to some other service.
public class Handler {
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private final Multimap<String, Long> clientidToTimestampHolder = ArrayListMultimap.create();
private static class Holder {
private static final Handler INSTANCE = new Handler();
}
public static Handler getInstance() {
return Holder.INSTANCE;
}
private Handler() {
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
processData();
}
}, 0, 60, TimeUnit.SECONDS);
}
// called by another thread to populate clientidToTimestampHolder map
public void add(final String clientid, final Long timestamp) {
clientidToTimestampHolder.put(clientid, timestamp);
}
// called by background thread
public void processData() {
for (Entry<String, Collection<Long>> entry : clientidToTimestampHolder.asMap().entrySet()) {
String clientid = entry.getKey();
Collection<Long> timestamps = entry.getValue();
for (long timestamp : timestamps) {
boolean isUpdated = isUpdatedClient(clientid, timestamp);
if (!isUpdated) {
updateClient(String.valueOf(clientid));
}
}
}
}
}
My question is, add
method will keep getting called every time from a different thread. So do I need to create a copy of clientidToTimestampHolder
map and pass that copy to processData()
method as a parameter instead of directly working on that map?
Because right now I am using the same map to populate data in it and then also iterate the same map to send stuff to some other service so I am not deleting data from that map so those entries will always be there in that map.
What is the best way to solve this problem? And I need to make sure it is thread safe and there is no race condition as I cannot loose any clientid
.
Update
So my processData
method will look like this?
public void processData() {
synchronized (clientidToTimestampHolder) {
Iterator<Map.Entry<String, Long>> i = clientidToTimestampHolder.entries().iterator();
while (i.hasNext()) {
String clientid = i.next().getKey();
long timestamp = i.next().getValue();
boolean isUpdated = isUpdatedClient(clientid, timestamp);
if (!isUpdated) {
updateClient(clientid);
}
i.remove();
}
}
}