Java Concurrency in app server - java

I have a small web application with CRUD operations. For the data, I can't use a db, so I must store it in a map or similar data structure. Based on the requirement, I need two maps to store and access the data, and I have to make sure they are in sync with each other.
Now, the question, what is the preferred way to make crud operations on the two maps on in a multi threaded environment making sure they are in consistent state. Is there a better approach or pattern to avoid locking and synchronization?
Thanks

I believe there has to be some synchronization involved. You can try the following approach.
First of all use a ConcurrentHashMap for both of your maps. Then encapsulate both your maps in an object that will have synchronized methods to ensure your data is in a consistent state. The following is an example:
public class ParentMap {
private ConcurrentHashMap<String, Object> map1 = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Object> map2 = new ConcurrentHashMap<>();
public synchronized void add(Object objectToAdd) {
// Add to map1
// Add to map2
}
public synchronized void update(String key, Object object) {
// Update the object based on the key on both maps (following the rules of your application)
}
public synchronized void delete(String key) {
// Delete in both maps following the rules of your application
}
public Object get(String key) {
// Use the rules of your application to read
}
}
Ensure that there is only one ParentMap object in your application. You may use the Singleton Pattern for this.

Related

Volatile to be used with Concurrent Collection?

I am developing a metrics store (Map) , which basically collects metrics about some operations such as
mix
max
counter
timeElapsed[] etc
Here Key is the name of the method and value are metrics about it.
Spring can help me create singleton object of MetricStore, i am using ConcurrentHashMap to avoid race condition when multiple REST request comes in parallel.
My query
1- Do i need to make MetricStore variable store volatile? to improve the visibility among multiple requests. 2- I am using Map as the base class and ConcurrentHashMap as Implemetnation, does it affect as Map is not ThreadSafe.
-
#Component
class MetricStore{
public Map<String, Metric> store = new ConcurrentHashMap<>();
//OR public volatile Map<String, Metric> store = new ConcurrentHashMap<>();
}
#RestController
class MetricController{
#Autowired
private MetricStore metricStore;
#PostMapping(name="put")
public void putData(String key, Metric metricData) {
if(metricStore.store.containsKey(key)) {
// udpate data
}
else {
metricStore.store.put(key, metricData);
}
}
#PostMapping(name="remove")
public void removeData(String key) {
if(metricStore.store.containsKey(key)) {
metricStore.store.remove(key);
}
}
}
Do i need to make MetricStore variable store volatile?
No, because you are not changing the value of store (i.e. store can be marked as final and the code should still compile).
I am using Map as the base class and ConcurrentHashMap as Implemetnation, does it affect as Map is not ThreadSafe
Because you're using a ConcurrentHashMap as the implementation of Map, it is thread-safe. If you want the declared type to be more specific, Map can be changed to ConcurrentMap.
The bigger issue here is that you're using containsKey before calling put and remove when you should be using compute and computeIfPresent, which are atomic operations:
#PostMapping(name="put")
public void putData(String key, Metric metricData) {
metricStore.store.compute(key, (k, v) -> {
if (v == null) {
return metricData;
}
// update data
});
}
#PostMapping(name="remove")
public void removeData(String key) {
metricStore.store.computeIfPresent(key, (k, v) -> null);
}

Are There Dangers to Writing to Ehcache in Parallel?

In the given example, I have an inner class that defines a read-through CacheLoaderWriter inside of an imagined ExampleCache class that would abstract cache operations so that 3rd parties just think they are access a data structure (key-value pair). My question involves the loadAll method.
If loadAll is written to write to EhCache in parallel, will there be any risks of record mutation or instability? Is EhCache built to handle user-defined concurrency?
class ExampleCacheLoader implements CacheLoaderWriter<String, ArrayList> {
private HashMap<String, ArrayList> map;
public CacheLoader() {
map = new HashMap<>();
}
#Override
public ArrayList<String> load(String s) throws Exception {
Map.Entry<String, ArrayList<String>> personEntry = getPersonAliases(s);
if(!map.containsKey(personEntry.getKey())){
map.put(personEntry.getKey(), personEntry.getValue());
}
return map.get(personEntry.getKey());
}
#Override
public Map<String, ArrayList> loadAll(
Iterable<? extends String> keys) throws Exception {
Map<String, ArrayList> localTempMap = new HashMap<>();
Stream keyStream = StreamSupport.stream(entries.spliterator(), true);
keyStream.forEach(key -> {
localTempMap.putIfAbsent(
getterExample(key).getKey(),
getterExample(key).getValue());
});
map.putAll(localTempMap);
return localTempMap;
}
.
.
.
Ehcache is a library designed for concurrent access and thus handles multi threading, concurrent mutations and related problems in the best possible way.
Now your understanding of the CacheLoaderWriter seems problematic. You are not supposed to access the cache from a CacheLoaderWriter instead the CacheLoaderWriter will be accessed by the cache when required, that is for the load* methods when a mapping is requested but not found in the cache.
However your CacheLoaderWriter implementation must be thread safe as Ehcache will use it concurrently. Also in your proposed implementation you are maintaining state inside the CacheLoaderWriter which is redundant with what the Cache will do ... if I understand correctly what you are trying to achieve.

How to populate map of string and another map in a thread safe way?

I am working on measuing my application metrics using below class in which I increment and decrement metrics.
public class AppMetrics {
private final AtomicLongMap<String> metricCounter = AtomicLongMap.create();
private static class Holder {
private static final AppMetrics INSTANCE = new AppMetrics();
}
public static AppMetrics getInstance() {
return Holder.INSTANCE;
}
private AppMetrics() {}
public void increment(String name) {
metricCounter.getAndIncrement(name);
}
public AtomicLongMap<String> getMetricCounter() {
return metricCounter;
}
}
I am calling increment method of AppMetrics class from multithreaded code to increment the metrics by passing the metric name.
Problem Statement:
Now I want to have metricCounter for each clientId which is a String. That means we can also get same clientId multiple times and sometimes it will be a new clientId, so somehow then I need to extract the metricCounter map for that clientId and increment metrics on that particular map (which is what I am not sure how to do that).
What is the right way to do that keeping in mind it has to be thread safe and have to perform atomic operations. I was thinking to make a map like that instead:
private final Map<String, AtomicLongMap<String>> clientIdMetricCounterHolder = Maps.newConcurrentMap();
Is this the right way? If yes then how can I populate this map by passing clientId as it's key and it's value will be the counter map for each metric.
I am on Java 7.
If you use a map then you'll need to synchronize on the creation of new AtomicLongMap instances. I would recommend using a LoadingCache instead. You might not end up using any of the actual "caching" features but the "loading" feature is extremely helpful as it will synchronizing creation of AtomicLongMap instances for you. e.g.:
LoadingCache<String, AtomicLongMap<String>> clientIdMetricCounterCache =
CacheBuilder.newBuilder().build(new CacheLoader<String, AtomicLongMap<String>>() {
#Override
public AtomicLongMap<String> load(String key) throws Exception {
return AtomicLongMap.create();
}
});
Now you can safely start update metric counts for any client without worrying about whether the client is new or not. e.g.
clientIdMetricCounterCache.get(clientId).incrementAndGet(metricName);
A Map<String, Map<String, T>> is just a Map<Pair<String, String>, T> in disguise. Create a MultiKey class:
class MultiKey {
public String clientId;
public String name;
// be sure to add hashCode and equals
}
Then just use an AtomicLongMap<MultiKey>.
Edited:
Provided the set of metrics is well defined, it wouldn't be too hard to use this data structure to view metrics for one client:
Set<String> possibleMetrics = // all the possible values for "name"
Map<String, Long> getMetricsForClient(String client) {
return Maps.asMap(possibleMetrics, m -> metrics.get(new MultiKey(client, m));
}
The returned map will be a live unmodifiable view. It might be a bit more verbose if you're using an older Java version, but it's still possible.

How to access a HashMap or ArrayList from any part of the application?

Every time I load certain values from database, a HashMap is loaded with certain keys and values from the database, how do I make this HashMap available to all the other classes without having to load the values repeatedly into the HashMap each time it is called:
This is the class which contains method where HashMap is loaded:
public class Codes {
List<CODES> List = null;
private CodesDAO codesDAO = new CodesDAO(); //DAO Class
public HashMap <MultiKey,String> fetchCodes(){
MultiKey multiKey;
HashMap <MultiKey,String> map = new HashMap<MultiKey,String>();
List = codesDAO.fetchGuiCodes();//fetches codes from DB
for(CODES gui:List){
multiKey = new MultiKey(gui.getCode(), gui.getKEY());
map.put(multiKey,gui.getDESC());
}
return map;
}
}
You can save your map in a static field, and initialize it in a static block. This way it is done only once:
public class Codes {
private static Map<MultiKey, String> codes;
static {
CodesDAO codesDAO = new CodesDAO(); // DAO Class
HashMap<MultiKey, String> map = new HashMap<MultiKey, String>();
List<CODES> list = codesDAO.fetchGuiCodes();// fetches codes from DB
for (CODES gui : list) {
MultiKey multiKey = new MultiKey(gui.getCode(), gui.getKEY());
map.put(multiKey, gui.getDESC());
}
codes = Collections.unmodifiableMap(map);
}
public static Map<MultiKey, String> fetchCodes() {
return codes;
}
}
Then you can retrieve the codes with:
Codes.fetchCodes();
If static fields are not an option, you could lazily initialise as follows:
private HashMap<MultiKey, String> map = null;
public HashMap<MultiKey, String> fetchCodes() {
if (map == null) {
map = new HashMap<MultiKey, String>();
list = codesDAO.fetchGuiCodes();// fetches codes from DB
for (CODES gui : list) {
MultiKey multiKey = new MultiKey(gui.getCode(), gui.getKEY());
map.put(multiKey, gui.getDESC());
}
}
return map;
}
Note: this is not thread-safe, but could be with some additional synchronization.
May be load the data only once? Use memoization(I would) from guava:
Suppliers.memoize(//Implementation of Supplier<T>)
If you use Spring, you could simply declare a bean (singleton) and implement the InitializingBean interface.
You would be forced to implement a method called afterPropertiesSet() and load your Map there.
If you don't use Spring, you could initialize your map at the start like you did and put it in
the servletConext. this scope is availbale from all session.
This is all good for read-only data. if you need to update it, be carefull because this will not be thread-safe. you will have to make it thread-safe.
hope it help
regards
I'm not sure how the OP designed his Java EE application and if any 3rd party frameworks are been used, but in a properly designed standard Java EE application using EJB, CDI, JPA, transactions and all on em, the DB is normally not available in static context. The answers which suggest to initialize it statically are in such case severely misleading and broken.
The canonical approach is to just create one instance holding the preinitialized data and reuse it throughout application's lifetime. With the current Java EE standards, this can be achieved by creating and initializing the bean once during application's startup and storing it in the application scope. For example, an application scoped CDI bean:
#Named
#ApplicationScoped
public class Data {
private List<Code> codes;
#EJB
private DataService service;
#PostConstruct
public void init() {
codes = Collections.unmodifiableList(service.getAllCodes());
}
public List<Code> getCodes() {
return codes;
}
}
This is then available by #{data.codes} anywhere else in the application.

How to retrieve content (keys) of a Java JCache object in a Google AppEngine application

Using Memcache Java API (http://code.google.com/appengine/docs/java/memcache/overview.html)
The JCache is not fully implemented and the methods values(), keySet() as well as entrySet() throw java.lang.UnsupportedOperationException
Anybody know of a workaround or have a working example using a lower-level API?
The only workaround I can see is to create another Cache instance with the goal to store under a known key an object containing keys, or any more complex structure.
This structure is modified in the onPut() and onRemove() methods of the used CacheListener:
public void onRemove(Object key)
{
LOG.log(Level.INFO, key.toString());
Map<Integer, Date> realEstateIdByDate = (Map<Integer, Date>) keyCache.get("realEstateIdByDate");
realEstateIdByDate.remove(key);
keyCache.put("realEstateIdByDate", realEstateIdByDate);
}
#Override
public void onPut(Object object)
{
LOG.log(Level.INFO, object.toString());
Map<Integer, Date> realEstateIdByDate = (Map<Integer, Date>) keyCache.get("realEstateIdByDate");
realEstateIdByDate.put(((RealEstateAd)object).getRealEstateId(), new Date());
keyCache.put("realEstateIdByDate", realEstateIdByDate);
}
Any feedback more than welcome ;-)

Categories