A concurrent issue among threads - java

Suppose I have a instance variable that has original value:
Integer mMyInt = 1;
There are two threads.
The first changes mMyInt by calling:
void setInt() {
mMyInt = 2;
}
The second thread gets mMyInt by calling:
Integer getInt() {
return mMyInt;
}
Both threads don't use synchronization.
My questions is, what is the possible value the the second thread can get from getInt()? Can it be only 1 or 2? Can it get null?
Thanks

EDIT: Important update thanks to #irreputable.
Unless the object has escaped during construction (see below), the assignment mMyInt=1 happens before any access to the getter/setter. Also in java, object assignment is atomic (there is 0 chance that you observe some invalid address assigned. Be careful because 64bit primitive assignments, such as double and long are NOT atomic).
So, in that case the possible value is either 1 or 2.
Object can escape during construction in this kind of situation:
class Escape {
Integer mmyInt = 1;
Escape(){
new Thread(){
public void run(){
System.out.println(Escape.this.mmyInt);
}
}.start();
}
}
Although in practice it probably rarely happens, in the above case, the new thread can observe an not fully constructed Escape object and thus in theory get an mmyInt value of null (AFAIK you still won't get some random memory location).
What if it it is a HashMap
object? The instance variable mMyMap
has original value. Then, the first
thread calls "mMyMap = new HashMap();"
The second thread calls "return
mMyMap;" Can the second thread get
null, or can it only get original or
new HashMap object?
When "Object reference assignment is atomic", it means that you will NOT observe an intermediate assignment. It's either the value before, or the value after. So if the only assignment that is happening is map = someNonNullMap(); after the construction has completed (and the field was assigned a non null value during the construction) and the object has not escaped during the construction, you can't observe null.
Update:
I consulted a concurrency expert, and according to him, the Java Memory Model allows compilers to reorder assignment and object construction (while in practice I imagine that would be highly unlikely).
So for example in the below case, thread1 can allocate some heap, assign some value to map, the continue construction of map. Meanwhile thread2 comes and observe an partially constructed object.
class Clever {
Map map;
Map getMap(){
if(map==null){
map = deriveMap(); }
return map;
}
}
JDK has a similar construct in the String class (not exact quote):
class String {
int hashCode = 0;
public int hashCode(){
if(hashCode==0){
hashCode = deriveHashCode();
}
return hashCode;
}
}
This DOES work because the non-volatile cache is primitive and not an object, according to the same concurrency experts.
These problems can be avoided by introducing an happens before relationship. In the cases above, one could do this by declaring the members volatile. Also for 64bit primitive, declaring them volatile will make their assignment atomic.

// somewhere
static YourClass obj;
//thread 1
obj = new YourClass();
// thread 2
if(obj!=null)
obj.getInt();
theoretically, thread 2 could get a null.

Related

Can we use AtomicInteger as a local variable in a method and achieve thread safety?

public void tSafe(List<Foo> list, Properties status) {
if(list == null) return;
String key = "COUNT";
AtomicInteger a = new AtomicInteger(Integer.valueOf(status.getProperty(key,"0")));
list.parallelStream().filter(Foo::check).
forEach(foo -> {status.setProperty(key, String.valueOf(a.incrementAndGet())); }
);
}
private interface Foo {
public boolean check();
}
Description:
In the above example, status is a shared properties and it contains a key with name COUNT. My aim is to increment count and put it back in properties to count the number of checks performed. Consider tSafe method is being called by multiple threads, Do I get the correct count at the end? Note that I've used AtomicInteger a as local variable.
If you only have one thread, this will work, however if you have more than one thread calling this, you have some operations which are thread safe. This will be fine provided each thread operates on different list and status objects.
As status is a thread safe collection, you can lock it, and provided the list is not changed in another thread, this would would.
In general, working with String as numbers in a thread safe manner is very tricky to get right. You are far better off making your value thread i.e. an AtomicInteger and never anything else.
No this will not guarantee thread safety. Even though incrementAndGet() is itself atomic, getting a value from the Properties object and setting it back is not.
Consider the following scenario:
Thread #1 gets a value from the Properties object. For argument's sake let's say it's "100".
Thread #2 gets a value from the Properties object. Since nothing has happened, this value is still "100".
Thread #1 creates an AtomicInteger, increments it, and places "101" in the Properties object.
Thread #2 does exactly the same, and places "101" in the Properties object, instead of the 102 you expected.
EDIT:
On a more productive note, a better approach would be to just store the AtomicInteger on your status map, and increment it inplace. That way, you have a single instance and don't have to worry about races as described above. As the Properties class extends Hashtable<Object, Object> this should technically work, although Properties really isn't intended for values that aren't Strings, and you'd be much better off with a modern thread safe Map implementation, such as a ConcurrentHashMap:
public void tSafe(List<Foo> list, ConcurrentMap<String, AtomicInteger> status) {
if(list == null) {
return;
}
String key = "COUNT";
status.putIfAbsent(key, new AtomicInteger(0));
list.parallelStream()
.filter(Foo::check)
.forEach(foo -> { status.get(ket).incrementAndGet(); });
}

Volatile array - memory visibility of the elements

Consider the code snippet
class A {
private Map<String, Object> taskMap = new HashMap<>();
private volatile Object[] tasksArray ;
// assume this happens on thread1
public void assignTasks() {
synchronized(taskMap){
// put new tasks into map
// reassign values from map as a new array to tasksArray ( for direct random access )
}
}
// assume this is invoked on Thread2
public void action(){
int someindex = <init index to some value within tasksArray.length>;
Object[] localTasksArray = tasksArray;
Object oneTask = localTasksArray[someindex];
// Question : is the above operation safe with respect to memory visibility for Object oneTask ?
// is it possible that oneTask may appear null or in some other state than expected ?
}
}
Question : is the operation Object oneTask = localTasksArray[someindex]; safe with respect to memory visibility for Object oneTask ?
is it possible that oneTask may appear null or in some other state than expected ?
My thoughts are these :
It is possible that thread2 may see oneTask as null or in some state other than expected. This is because , even though the taskArray is volatile , and a read of this array will ensure proper visibility of the array itself , this does not ensure the visibility of the state internal to the object oneTask.
The volatile keyword only protects the field taskArray which is a reference to an Object[]. Whenever you read or write this field, it will have consistent ordering. However, this doesn't extend to the array referenced nor the objects that array references.
Most likely you want AtomicReferenceArray instead.
As far as I recall (I am researching now to confirm), Java only guarantees the volatile object itself is flushed to RAM, not sub parts of that object (as in array entries) or sub-fields of the object (in the case of objects).
However - I believe most (if not all) JVMs implement volatile access as a memory barrier (see here and the referenced page The JSR-133 Cookbook for Compiler Writers). As a memory barrier this therefore means that all previous writes by other threads will be flushed from cache to main memory when the access occurs - thus making all memory consistent at that time.
This should not be relied upon - if it is crucial that you have complete control of what is visible and what is not you should use one of the Atomic classes such as AtomicReferenceArray as suggested by others. These may even be more efficient than volatile for exactly this reason.
Declaring a field volatile ensures that any write of that variable synchronizes-with (and is therefore visible to) any subsequent (according to synchronization order) of this value. Note that there is no such thing as a volatile object, or a volatile array. There are only volatile fields.
Therefore, in your code, there is no happens-before relationship between Thread 1 storing an object into the array, and Thread 2 reading it from there.

Thread safety issues in reference assignment using method call

I have the following code:
class SomeClass {
private Map<String, String> someMap = null;
public String getValue(String key) {
if (someMap == null) {
someMap = initialize(); // initialize() is some method which returns a proper map.
}
return someMap.get(key);
}
}
Assuming I don't care about someMap getting initialized more than once, are there any other thread-safety issues that I need to be concerned about here.
As per what-operations-in-java-are-considered-atomic , Reference assignment is certainly atmoic. Is the assignment to someMap guaranteed to happen after the method call to initialize() (seems logical to me). Is there any possibility that a thread can see a partially constructed someMap. Does it matter if instead of a map, I have some other type of object.
The code is not thread-safe. If two threads invoke the method getValue on the same object, it is possible, that one thread sees a partially created someMap.
In order to avoid this problem, you have to remove the data races. The simplest solution is to declare someMap as volatile. The simple rule to remember is: If the code contains no data races, then all executions will appear to be sequentially consistent.
Its not a Thread Safe even if you put volatile because if two threads are called getValue method at a same time, the following scenario can happen
1) Thread 1 & Thread 2 check if (someMap == null) , both will pass and try to reinitialise.
2) Both will reinitialize the reference. Thread 1 return the old reference which one is override by thread 2 .
3) So please refer the link Double Checked Locking in Singleton

Client/server multithreading and ConcurrentHashMap - why isn't clients.get(id) being locked?

I have the following block of code in my server:
clients.putIfAbsent(id, new Integer(0));
synchronized (clients.get(id)) {
if (o instanceof Integer) {
x = new Integer(((Integer) o).intValue());
value = clients.get(id); // existing value in HashMap
value = new Integer(value.intValue() + x);
clients.put(id, value);
} else if (o instanceof String) {
clients.put(id, new Integer(0));
}
Thread.sleep(SockServer5.sleepTime);
out.writeObject(clients.get(id));
out.flush();
}
clients is a ConcurrentHashMap, while o is the object input being read from the client. For each new client connection, the server spawns a new thread.
I would like to know, is there any particular reason why my clients.get(id) isn't being locked?
It is really hard to understand what you are trying to achieve, clients.get(id) returns an instance of an Object and you are synchronizing on it.
Fine.
That does not prevent access to the concurrent hashmap by another thread. I suspect you want to prevent access to the Hashmap, in which case you should use an Object() as a mutex
In both branches of your if statement, you are putting a new object into the map. Therefore all other threads will find a different object as result of client.get(id). Even if you have two equal integers in the map, they are not same objects.
Example: if 'o' is always a string, each execution of the code will replace the value in the map, and each following thread will get a new object in client.get() (well some may be lucky enough to get a previous object, but most will get a new one, since the synchronized block is rather small and fast comparing to stream handling and your sleep (because the object gets replaced, before the sleep finishes)).
If you want to synchronize on a non-existing object, on the idea (or id) of the object, check out this github repo: https://github.com/anotheria/idbasedlock
Two things: first
One shall not use new Integer but Integer.valueOf(i)
The other thing is that there isn't even a need to use synchronized. It completely defies the reason to use a concurrent map, because it throttles down threads to single-threaded thanks to blocking. Here is a solution that does not use synchronized but is still thread-safe:
clients.putIfAbsent(id, Integer.valueOf(0));
Integer value;
do {
value = clients.get(id);
} while (clients.replace(id, value, value + o) == false); // repeat until value did not change in between
Thread.sleep(SockServer5.sleepTime);
out.writeObject(value);
out.flush();
Where clients is defined as (replace String with whatever you use):
final ConcurrentHashMap<String, Integer> clients;
This uses the same concept as compareAndSet does in other Atomics: it repeats until no thread interfered in between. The big benefit is that no thread needs to be blocked, so on a multi-core machine all cores can be used at 100% all the time.
Please note as well the usage of automatic boxing of Integers in value + o. Java will use the most efficient form here on its own.

Safe Publication of Java object after calling setter on the object

Will calling a setter after constructor execution but before returning the reference will be a safe publication ?
public class SafePublication {
private int i = 0;
private SafePublication() {
i = 10;
}
// Here we are calling setter are object creation.
//Will this change be visible to other threads
public static SafePublication getInstance() {
SafePublication pub = new SafePublication();
pub.setVal(20);
return pub;
}
private void setVal(int x) {
this.i = x;
}
}
No it won't be safe.
The setVal method is not synchronized, and i is not volatile. Therefore, there will be no synchronization point between an update to i (via setVal) and any code run on another thread that reads i. The fact that the setVal call happens in the thread that constructs the instance makes on difference.
The bottom line is that another thread may see the value of i as any one of 0, 10 or 20.
How may another thread see that value if the reference to the object has not been returned yet?
It is not. The problem is that the other thread may not see the correct value of i.
I think you are confusing this situation with the case where the field is final. There, the JLS does specify that the field is safely published. The problem is that this guarantee does not apply to non-final fields; see JLS 17.5. The wording is as follows:
"An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields. "
(Emphasis added)
i would rather say another thread may see the value of i as any one of 10 or 20. It is guaranteed not to see 0.
AFAIK, there is nothing in JLS 17.4 or JLS 17.5 that offers that guarantee. The only thing that is guaranteed is that nothing will see the value of i before default initialization has taken place. (Please feel free to prove me wrong ... with references to the JLS.)

Categories

Resources