ConcurrentHashMap as singletone cache with synchronized - java

how do you think, do we need to use synchronized block for better optimization of access to instance of Ad?
The instance of Ad.class can be retrieved from different threads. Synchronized helps to get an instance in one time with one get operation from ConcurrentHashMap. ConcurrentHashMap store all values as volatile. I use it on java 1.7 for android, computeIfAbsent is available in java 1.8.
It will be great to get detailed answer, why not or why yes.
Thank you!
public final class Ad {
private final static Map<String, Ad> ads = new ConcurrentHashMap<>();
public static Ad get(#NonNull String appId) {
if (appId == null) appId = "";
boolean containsAd = ads.containsKey(appId);
Ad localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
synchronized (Ad.class) {
containsAd = ads.containsKey(appId);
localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
localInstance = new Ad();
localInstance.setAdId(appId);
ads.put(appId, localInstance);
}
}
}
return localInstance;
}
private Ad() {
}
}
UPDATE: Thanks to all for help. I replaced ConcurrentHashMap to HashMap.

This is not quite optimal. If multiple threads try initialize values at the same time, then they will block each other, even if they are looking for different keys.
You should use ConcurrentHashMap.computeIfAbsent to check for the add and create missing ones in a single step. That way you will not create any Ads that aren't used, and two threads will only block each other if they're trying to initialize the same entry:
public static Ad get(#NonNull String appId) {
if (appId == null) appId = "";
return ads.computeIfAbsent(appId, Ad::new);
}
private Ad(String appId) {
this();
setAdId(appId);
}

From what I understand what you actually want to achieve is putIfAbsent and as such this is much simpler then what you do (your are using a double check locking):
public static Ad get(String appId) {
String newId = appId == null ? "" : appId;
ads.putIfAbsent(newId, new Ad());
return map.get(newId);
}

Related

How to clone old builder to make a new builder object?

I have a builder class which I am using in one of my project.
Let's say I have metricA as builder based on below class.
I need to make a new builder metricB based on metricA by cloning metricA so that metricB contains all the values which were already there in metricA.
In the constructor of MetricHolder I am initializing some fields (which are not set directly) basis on fields that have been set already.
clientTypeOrPayId - I am initializing this field. If payId is present, then I will set this value or I will set clientType.
clientKey - I am initializing this field as well in the same constructor.
And most importantly, I am putting few mandatory fields in the clientPayload map. I am not sure what is the right way to do that. But I need to add is_clientid and is_deviceid into the map. (In general I am adding few more fields).
And then in the last of the constructor, I am calculating latency difference and sending it to some other system.
Below is my class:
public final class MetricHolder {
private final String clientId;
private final String deviceId;
private final String payId;
private final String clientType;
private final String clientTypeOrPayId;
private final Schema schema;
private final String schemaId;
private final String clientKey;
private final Map<String, String> clientPayload;
private final Record record;
private final long clientCreateTimestamp;
private final long clientSentTimestamp;
private MetricHolder(Builder builder) {
this.payId = builder.payId;
this.siteId = builder.siteId;
this.clientType = builder.clientType;
this.clientId = builder.clientId;
this.deviceId = builder.deviceId;
this.schema = builder.schema;
this.schemaId = builder.schemaId;
// populating all the required fields in the map and make it immutable
// not sure whether this is right?
builder.clientPayload.put("is_clientid", (clientId == null) ? "false" : "true");
builder.clientPayload.put("is_deviceid", (clientId == null) ? "true" : "false");
this.clientPayload = Collections.unmodifiableMap(builder.clientPayload);
this.clientTypeOrPayId = Strings.isNullOrEmpty(payId) ? clientType : payId;
this.record = builder.record;
this.clientKey = "process:" + System.currentTimeMillis() + ":"
+ ((clientId == null) ? deviceId : clientId);
this.clientCreateTimestamp = builder.clientCreateTimestamp;
this.clientSentTimestamp = builder.clientSentTimestamp;
// this will be called twice while cloning
// what is the right way to do this then?
SendData.getInstance().insert(clientTypeOrPayId,
System.currentTimeMillis() - clientCreateTimestamp);
SendData.getInstance().insert(clientTypeOrPayId,
System.currentTimeMillis() - clientSentTimestamp);
}
public static class Builder {
private final Record record;
private Schema schema;
private String schemaId;
private String clientId;
private String deviceId;
private String payId;
private String clientType;
private Map<String, String> clientPayload;
private long clientCreateTimestamp;
private long clientSentTimestamp;
// this is for cloning
public Builder(MetricHolder packet) {
this.record = packet.record;
this.schema = packet.schema;
this.schemaId = packet.schemaId;
this.clientId = packet.clientId;
this.deviceId = packet.deviceId;
this.payId = packet.payId;
this.clientType = packet.clientType;
// make a new map and check whether mandatory fields are present already or not
// and if they are present don't add it again.
this.clientPayload = new HashMap<>();
for (Map.Entry<String, String> entry : packet.clientPayload.entrySet()) {
if (!("is_clientid".equals(entry.getKey()) || "is_deviceid".equals(entry.getKey())) {
this.clientPayload.put(entry.getKey(), entry.getValue());
}
}
this.clientCreateTimestamp = packet.clientCreateTimestamp;
this.clientSentTimestamp = packet.clientSentTimestamp;
}
public Builder(Record record) {
this.record = record;
}
public Builder setSchema(Schema schema) {
this.schema = schema;
return this;
}
public Builder setSchemaId(String schemaId) {
this.schemaId = schemaId;
return this;
}
public Builder setClientId(String clientId) {
this.clientId = clientId;
return this;
}
public Builder setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
public Builder setPayId(String payId) {
this.payId = payId;
return this;
}
public Builder setClientType(String clientType) {
this.clientType = clientType;
return this;
}
public Builder setClientPayload(Map<String, String> payload) {
this.clientPayload = payload;
return this;
}
public Builder setClientCreateTimestamp(long clientCreateTimestamp) {
this.clientCreateTimestamp = clientCreateTimestamp;
return this;
}
public Builder setClientSentTimestamp(long clientSentTimestamp) {
this.clientSentTimestamp = clientSentTimestamp;
return this;
}
public MetricHolder build() {
return new MetricHolder(this);
}
}
// getters
}
Question:-
Below is how I make metricA builder object:
MetricHolder metricA = new MetricHolder.Builder(record).setClientId("123456").setDeviceId("abcdefhg")
. setPayId("98765").setClientPayload(payloadMapHolder).setClientCreateTimestamp(createTimestamp)
.setClientSentTimestamp(sentTimestamp).build();
Now this is how I clone the metricA object later on in the code when I get all other fields as shown below:
MetricHolder metricB = new MetricHolder.Builder(metricA).setSchema(schema).setSchemaId("345").build();
I see two problem now:
First of all, my SendData.getInstance() line in the MetricHolder constructor will be called twice. First is when I make metricA and second when I make metricB by cloning metricA. But I just want to call it only once when I try to create metricA builder object? How can I make this possible?
Second is, the way I am populating clientPayload map with two mandatory fields in the MetricHolder constructor doesn't look right to me. Is there any other better way to do the same thing?
I guess the whole problem is happening because the way I am cloning metricA to make a metricB builder object? What is the best way to do this? I want to achieve above two things but in a right way.
But I just want to call it only once when I try to create metricA builder object? How can I make this possible?
The most straightforward way is to have a flag in the builder indicating whether it was created by Record or by cloning:
class Builder {
final boolean cloned;
Builder(MetricHolder packet) {
this.cloned = true;
// ...
}
Builder(Record record) {
this.cloned = false;
// ...
}
}
Then, in the constructor of MetricHolder:
if (!builder.cloned) {
SendData.getInstance().whatever();
}
But it's worth pointing out that making this call to SendData is an example of doing too much work in the constructor. You should think carefully about whether you really want to be making this call in the constructor, or whether you can factor that out into another method.
Second is, the way I am populating clientPayload map with two mandatory fields in the MetricHolder constructor doesn't look right to me. Is there any other better way to do the same thing?
You've misunderstood the "unmodifiable" bit of using Collections.unmodifiableMap: it's only an unmodifiable view of the map parameter; you can still modify the underlying map.
Here's a JUnit test to demonstrate:
Map<String, String> original = new HashMap<>();
original.put("hello", "world");
// Obviously false, we just put something into it.
assertFalse(original.isEmpty());
Map<String, String> unmodifiable = Collections.unmodifiableMap(original);
// We didn't modify the original, so we don't expect this to have changed.
assertFalse(original.isEmpty());
// We expect this to be the same as for the original.
assertFalse(unmodifiable.isEmpty());
try {
unmodifiable.clear();
fail("Expected this to fail, as it's unmodifiable");
} catch (UnsupportedOperationException expected) {}
// Yep, still the same contents.
assertFalse(original.isEmpty());
assertFalse(unmodifiable.isEmpty());
// But here's where it gets sticky - no exception is thrown.
original.clear();
// Yep, we expect this...
assertTrue(original.isEmpty());
// But - uh-oh - the unmodifiable map has changed!
assertTrue(unmodifiable.isEmpty());
The thing is that the map is only unmodifiable if there is no other reference to it hanging around: if you don't have a reference to original, unmodifiable actually is unmodifiable; otherwise, you can't rely upon the map never changing.
In your particular case, you are simply wrapping the clientPayload map in your unmodifiable collection. So, you're overwrite values for previously-constructed instances.
For example:
MetricHolder.Builder builder = new MetricHolder.Builder();
MetricHolder first = builder.build();
assertEquals("false", first.clientPayload.get("is_clientid"));
assertEquals("true", first.clientPayload.get("is_deviceid"));
builder.setClientId("").build();
// Hmm, first has changed.
assertEquals("true", first.clientPayload.get("is_clientid"));
assertEquals("false", first.clientPayload.get("is_deviceid"));
The correct approach is not to wrap builder.clientPayload. Take a copy of the map, modify it, and then wrap with unmodifiableMap:
{
Map<String, String> copyOfClientPayload = new HashMap<>(builder.clientPayload);
copyOfClientPayload.put("is_clientid", (clientId == null) ? "false" : "true");
copyOfClientPayload.put("is_deviceid", (clientId == null) ? "true" : "false");
this.clientPayload = Collections.unmodifiableMap(copyOfClientPayload);
}
The surrounding {} aren't strictly necessary, but they restrict the scope of copyOfClientPayload, so you can't accidentally reuse it later in the constructor.

Changes in Java 6 synchronization?

I am looking at some code that is causing an issue (Deadlock) in Java 6 and above, but not in Java 1.5.
BMP Bean:
private MyClass m_c;
public String ejbCreate(String id) throws CreateException, MyException
{
try
{
m_c = Singleton.getInstance().getObj(id);
}
catch (MyException e)
{
synchronized (Singleton.getInstance())
{
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
}
else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
Singleton:
private Map objCache = new HashMap();
private static Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
public void addObj(String id, MyClass o)
{
if (this.objCache.containsKey(id)) {
this.objCache.remove(id);
}
this.objCache.put(id, o);
}
public MyClass getObj(String id) throws Exception
{
MyClass o = null;
o = (MyClass)this.objCache.get(id);
if (o == null) {
throw new MyException("Obj " +id+ " not found in cache");
}
return o;
}
public boolean hasObj(String id)
{
return this.objCache.containsKey(id);
}
The empirical evidence so far shows that putting synchronization round the whole try/catch resolves the deadlock when using Java 6.
Clearly there can be one or more threads calling
Singleton.getInstance().getObj(id)
without obtaining the lock whilst another thread has the lock and is executing the code in the synchronized block, but even after considering memory synchronization detailed in JSR-133, it doesn't look like there should be any issues in this scenario.
I am aware that I haven't explained what the issue is apart from saying it is a deadlock and that it is not ideal to paint only a prat of the picture but to paint the whole picture would take a very big canvas.
I have looked at the notes for Java 6 release and the only area that sounds relevant is around uncontended synchronization, but I do not know if that is significant in this case.
Thank you for any help.
I suspect you are not getting a deadlock (holding two locks in two different threads obtained in a different order), but rather going into an infinite loop. This can happen with HashMap if you are accessing it in a manner which is not thread safe. What happens in the linked list used to handle collisions appears to go back on itself and the reader runs forever. This has always been an issue, though some subtle difference in Java 6 could show up this problem when a different version might not.
I suggest you fix this class so it uses a thread safe collection and not retry on Exception because there is not guarantee this will happen.
There is a lot you could do to improve this class but what you really need is ConcurrentMap.computeIfAbsent added in Java 8.
Note: there is no reason to
check a key exists before attempting to remove it.
remove a key just before attempting to put it.
throw an Exception instead of returning null.
returning null when you can pass it a factory. (as per computeIfAbsent)
use a factory when the type is known in advance.
I suggest you
use a ConcurrentMap for thread safe concurrent access.
use an enum for a Singleton.
Both of these were added in Java 5.0.
public enum MyClassCache {
INSTANCE;
private final Map<String, MyClass> cache = new ConcurrentHashMap<>();
public boolean hasId(String id) {
return cache.containsKey(id);
}
public MyClass get(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) throw new IllegalStateException(id);
return ret;
}
public MyClass getOrCreate(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) {
synchronized (cache) {
ret = cache.get(id);
if (ret == null) {
cache.put(id, ret = new MyClass(id));
}
}
}
return ret;
}
}
In Java 8 you can use computeIfAbsent
public MyClass getOrCreate(String id) {
return cache.computeIfAbsent(id, MyClass::new);
}
Am I right that the core of this question is the difference between:
public void ejbCreate1(String id) throws Exception {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
synchronized (Singleton.getInstance()) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
and
public void ejbCreate2(String id) throws Exception {
synchronized (Singleton.getInstance()) {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
in Java-6 that can cause the first to hang and the second to work fine.
Clearly the primary difference is that getObj might be called by two different threads at the same time, and may even be called while another threads is creating the new object.
From Is it safe to get values from a java.util.HashMap from multiple threads (no modification)? it is likely that you are not in that situation. Conclusion is that one thread is readng from the Map (perhaps o = (MyClass) this.objCache.get(id);) while another is writing to the map by calling addObj. This is clearly a recipe for the read to crash and burn.
See Is a HashMap thread-safe for different keys? for details about the potential sinkholes.

Hazelcast client singleton

I have a web app that will access a distributed map via the Hazelcast client on each doPost() to the servlet. My question is should I use a Singleton to access the client from all the different servlets, and is this thread safe?
This is my class Singleton class:
public class HazelcastDistributedCacheClientSingleton {
//Properties from FrameworkResources.properties file.
private static String hazelcastEnvironmentName = null;
private static final String mapName = "wfc";
//COnstructor
private HazelcastDistributedCacheClientSingleton() {
}
//Get the Map
public static IMap<String, Object> getMap() {
// Make sure we have a name for the IMap
if (hazelcastEnvironmentName == null) {
hazelcastEnvironmentName = "DEV";
}
return getHazelcastClient().getMap(mapName);
}
public static Object getSessionObj(String key){
return getMap().get(key);
}
public static void setSessionObj(String key, Object value){
getMap().set(key, value);
}
public static void removeSessionObj(String key){
getMap().remove(key);
}
//The client singleton
private static HazelcastInstance hzClientInstance = null;
// Get the client singleton
public static HazelcastInstance getHazelcastClient() {
// Create a client instance if not already exists
if (hzClientInstance == null) {
// Create a synchronized block
synchronized (new Object()) {
// Double check that we did not do this in another thread
if (hzClientInstance == null) {
//Get startup parms from config file
try {
hazelcastEnvironmentName = java.util.ResourceBundle.getBundle("FrameworkResources").getString("HazelcastEnvironmentName");
} catch (MissingResourceException e) {
hazelcastEnvironmentName = "DEV";
}
// Configure Client
ClientConfig clientConfig = new ClientConfig();
// Set the group name to segregate dev, test, prod caches
clientConfig.getGroupConfig().setName(hazelcastEnvironmentName).setPassword(hazelcastEnvironmentName);
hzClientInstance = HazelcastClient.newHazelcastClient(clientConfig);
}
} //end synchronized block
}
// Return the client instance
return hzClientInstance;
}
}
HazelcastInstances (client or server) are threadsafe and are designed to be shared between threads. It is best to make it a singleton.
A few comments:
1: make sure hzClientInstance is volatile. Otherwise you will have a broken the double checked locking implementation. Probably you also want to make hazelcastEnvironmentName volatile.
2: you can't synchronize on synchronized new Object()) since this object will not be shared between threads. I would synchronize on 'this' or create a lock object as final field in the HazelcastDistributedCacheClientSingleton
3: don't retrieve the IMap every time you need it. Put it in a (volatile) field the first time you retrieve it.

Cleaner way to filter collections in Java 7/Guava?

I have the following classes:
class ServiceSnapshot {
List<ExchangeSnapshot> exchangeSnapshots = ...
...
}
class ExchangeSnapshot{
Map<String, String> properties = ...
...
}
SayI have a collection of ServiceSnapshots, like so:
Collection<ServiceSnapshot> serviceSnapshots = ...
I'd like to filter the collection so that the resulting collection of ServiceSnapshots only contains ServiceSnapshots that contain ExchangeSnapshots where a property on the ExchangeSnapshots matches a given String.
I have the following untested code, just wondering is there a cleaner/more readable way to do this, using Java 7, and maybe Google Guava if necessary?
Updtae: Note also that the code sample I've provided below isn't suitable for my purposes, since I'm using iterator.remove() to filter the collection. It turns out I cannot do this as it is modifying the underlying collection , meaning subsequent calls to my method below result in fewer and fewer snashots due to previous calls removing them from the collection - this is not what I want.
public Collection<ServiceSnapshot> getServiceSnapshotsForComponent(final String serviceId, final String componentInstanceId) {
final Collection<ServiceSnapshot> serviceSnapshots = getServiceSnapshots(serviceId);
final Iterator<ServiceSnapshot> serviceSnapshotIterator = serviceSnapshots.iterator();
while (serviceSnapshotIterator.hasNext()) {
final ServiceSnapshot serviceSnapshot = (ServiceSnapshot) serviceSnapshotIterator.next();
final Iterator<ExchangeSnapshot> exchangeSnapshotIterator = serviceSnapshot.getExchangeSnapshots().iterator();
while (exchangeSnapshotIterator.hasNext()) {
final ExchangeSnapshot exchangeSnapshot = (ExchangeSnapshot) exchangeSnapshotIterator.next();
final String foundComponentInstanceId = exchangeSnapshot.getProperties().get("ComponentInstanceId");
if (foundComponentInstanceId == null || !foundComponentInstanceId.equals(componentInstanceId)) {
exchangeSnapshotIterator.remove();
}
}
if (serviceSnapshot.getExchangeSnapshots().isEmpty()) {
serviceSnapshotIterator.remove();
}
}
return serviceSnapshots;
}
Using Guava:
Iterables.removeIf(serviceSnapshots, new Predicate<ServiceSnapshot>() {
#Override
public boolean apply(ServiceSnapshot serviceSnapshot) {
return !Iterables.any(serviceSnapshot.getExchangeSnapshots(), new Predicate<ExchangeSnapshot>() {
#Override
public boolean apply(ExchangeSnapshot exchangeSnapshot) {
String foundComponentInstanceId = exchangeSnapshot.getProperties().get("ComponentInstanceId");
return foundComponentInstanceId != null && foundComponentInstanceId.equals(componentInstanceId);
}
});
}
});
I may have a ! missing or inverted somewhere, but the basic strategy is to remove any ServiceSnapshot objects that do not have any ExchangeSnapshot whose ID matches.

Is Map<String,AtomicLong> enough to be thread safe?

I have a very simple class:
public class IdProvider {
private Map<String,AtomicLong> idMap;
public IdProvider(){
idMap = new HashMap<>();
}
public long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
}
Different methods asynchronously may pass the same conversation identifier and call getAvailableId() where they will be returned a unique id.
Is this thread safe? I'm I guaranteed that the no two methods will receive the same id or do I need to opt for something else?
There's multiple ways to make this thread safe, but below is the simplest, I think. First, you need to safely publish the initial Map. Then you need to make each access of that map thread safe.
public class IdProvider {
private final Map<String,AtomicLong> idMap;
public IdProvider(){
idMap = new HashMap<>();
}
public synchronized long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
}
The final keyword is one way to provide "safe publication". (That's an actual term in Java, look it up.)
And without being tricky, just synchronizing the whole method is the easiest way to provide both synchronization and atomicity. You shouldn't try to do more unless you can profile this code and determine that it is in fact a performance bottle-neck. Keep It Simple.
This isn't thread safe.
public long getAvailableId(String conversation){
AtomicLong id = idMap.get(conversation);
// Thread could be paused here, causing bad interleavings
// If now a similar call to "getAvailableId" is done you will have two times the same id
if(id == null){
id = new AtomicLong(0);
idMap.put(conversation,id);
}
return id.getAndIncrement();
}
Make the method synchronized to avoid possible bad interleavings and data races.
When you need to use multiple providers working on same set of ids at the same time,
public class IdProvider {
private static Map<String,Long> idMap;
static
{
idMap = new HashMap<>();
}
public Object lock=new Object();
public IdProvider(Object l){
lock=l;
}
public long getAvailableId(String conversation){
// do other work
synchronized(lock)
{
Long id = idMap.get(conversation);
if(id == null){
id = new Long(0);
idMap.put(conversation,id);
}
return idMap.put(conversation,id+1);
}
}
}
Object lock=new Object();
... in a thread:
IdProvider provider=new IdProvider(lock); // providing from a thread
... in another thread:
IdProvider provider2=new IdProvider(lock); // providing from another

Categories

Resources