Reputation: 1922
Okay, so I realize that all threads share the heap, which contains all the objects that have been allocated for a java program. this means if multiple threads try to allocate a new object, then they might mess each other up and cause a segmentation fault. After reading some other threads, I still don't really understand if there's a lock free, safe way to construct objects inside of a thread. I'm trying to implement a lock free hashmap in java for a school project, and need to figure out if the constructor calls I make are thread safe or not. And if not, is there some kind of workaround, or memory management technique I can use to make things work?
here's what my internal classes look like
public class dataNode<T> extends node<T>{
int hash;
T data;
public dataNode(int _hash, T _value){
this.isArrayNode = false;
this.hash = _hash;
this.data = _value;
}
}
And the other class internal for my lock free hashmap:
import java.util.concurrent.atomic.*;
public class arrayNode<T> extends node<T>{
//this is an array where elements consist of datanodes and arraynodes
AtomicStampedReference<node<T>> [] array;
public arrayNode(int size){
this.isArrayNode = true;
array = new AtomicStampedReference[size];
for (int i = 0; i < size; i++){
array[i] = new AtomicStampedReference<node<T>>(null, concurMap.UNINITIALIZED);
}
}
}
Upvotes: 3
Views: 1000
Reputation: 2105
tl;dr Your JVM will handle memory allocation across threads for you.
Different JVMs may do things slightly differently. JRockit, for instance, has a few ways of allocating memory to new objects. It splits objects up into small and large objects. For 'small' objects (you can define this in your JVM at startup using -XXtlaSize
and -XXlargeObjectLimit
), the JVM allocates the object to a local thread area (TLA) that only that thread can allocate objects to. Once the thread local memory runs out, the thread can just request a new chunk.
For larger Objects, the JVM uses a bunch of tricks to avoid having to lock as much as possible when allocating, and those objects are allocated directly to the heap. One way is the JVM breaks up memory into different sized chunks it keeps in a cache, allowing it to assign a reasonable amount of memory quickly without having to lock on every byte it requires on the heap.
Your JVM may differ in exactly how it does it, but it would use similar strategies. Long story short, there's no need to lock when creating objects (unless your constructor code is not thread safe of course). There's more info here: https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html
Both of your constructors look fine. One thing I would point out (sorry if you know this already) is that the objects inside a thread safe data structure are not necessarily thread safe. So AtomicStampedReference will nicely look after adding, comparing, getting and setting objects (into the stamped reference that is, not the array), it won't look after the actual object if you modify it directly. For instance, the following won't be thread safe:
array[0].getReference().setHash(6);
You'll have to make sure you get the reference, create a new object, and then compare and set to make a change:
int oldStamp = array[0].getStamp();
int newStamp = oldStamp + 1;
DataNode<T> old = array[0].getReference();
DataNode<T> newDn = new DataNode<T>(6, old.value);
if (!array[0].compareAndSet(old, newDn, oldStamp, newStamp)) {
// If this fails, either the stamp, reference, or both have changed. Try again.
}
Upvotes: 1
Reputation: 60818
This means if multiple threads try to allocate a new object, then they might mess each other up and cause a segmentation fault.
I've never thought about this, but I think I have enough Java experience to say that's just false. Creating an object is threadsafe.
However, the constructor for the object you are creating must of course consist of threadsafe code.
Upvotes: 10