Before answering your question lets clear few terms related to Multi-Threaded environments to understand the basic things.
Race-Condition : When two or more thread trying to perform read or write operations on same variable on same time (here same variable = shared data between thread) eg. In your question Thraed-A
execute b = a + 10
which is write operation on b and At same time Thread-B can execute b*c
which is read operation on b. So here race condition is happening.
We can handle race condition by using two ways one is by using Synchronized method or block
and second by using Volatile
Keyword.
Volatile : Volatile keyword in Java guarantees that the value of the volatile variable will always be read from the main memory and not from Thread’s local cache. Normal variable without Volatile keyword is temporarily stored in Local cache for quick access and easy read write operations. Volatile doesn't block your thread it just make sure the write and read operation is perform in the sync. In the context of your example we can avoid race condition by making all variable as volatile
Synchronized : Synchronization is achived by blocking of thread. It means it use lock and key mechanism in such a way that only one thread can execute this block of code at a time. So Thread-B is waiting in the doors of syncronized block until Thread-A finish completely and release key. if you use syncronized in front of static method then lock is considered on your class (.class) and if method is non static or instance method (same as your case) at that time lock is considered on instance of class or current object read
Now come to the point lets modify your example with few print statements and kotlin code
class SharedData {
var a: Int
var b: Int
var c: Int
var d = 10
init {
c = d
b = c
a = b
}
@Synchronized
fun compute() : Pair<Int,Int>{
a = b * 20
b = a + 10
return a to b
}
@Synchronized
fun getComputationResult() : Int{
return b * c
}
}
@Test
fun testInstanceNotShared (){
println("Instance Not Shared Example")
val threadA = Thread{
val pair = SharedData().compute()
println("Running inside ${Thread.currentThread().name} compute And get A = ${pair.first}, B = ${pair.second} ")
}
threadA.name = "threadA"
threadA.start()
val threadB = Thread{
println("Running inside ${Thread.currentThread().name} getComputationResult = ${SharedData().getComputationResult()}")
}
threadB.name = "threadB"
threadB.start()
threadA.join()
threadB.join()
}
// Output
//Instance Not Shared Example
//Running inside threadB getComputationResult = 100
//Running inside threadA compute And get A = 200, B = 210
@Test
fun testInstanceShared (){
println("Instance Shared Example")
val sharedInstance = SharedData()
val threadA = Thread{
val pair = sharedInstance.compute()
println("Running inside ${Thread.currentThread().name} compute And get A = ${pair.first}, B = ${pair.second} ")
}
threadA.name = "threadA"
threadA.start()
val threadB = Thread{
println("Running inside ${Thread.currentThread().name} getComputationResult = ${sharedInstance.getComputationResult()}")
}
threadB.name = "threadB"
threadB.start()
threadA.join()
threadB.join()
}
//Instance Shared Example
//Running inside threadB getComputationResult = 2100
//Running inside threadA compute And get A = 200, B = 210
From above two test case you can identify that answer to your question is actually hidden in way how you call those methods (compute, getComputationResult) in multi-threaded environment.
After the execution of compute, will threadA update main memory
There is no guarantee that threadA Update the value of variable a,b,c,d on main memory but if you use Volatile keyword in front of those variable then it gives you 100% guarantee that those variable is updated with correct state immediately after modification happen
before executing getResult will threadB get only the value of b and c from main memory or will it clear the cache and fetch values for all member variables a,b,c and d
No
Addition to this - if you notice that in second test example even when two thread call the method same time you will get exact result. Means calling compute, getComputationResult same time still the getComputationResult method return the updated value from compute method this is because Synchronized and Volatile provide functionality called happens before which make sure that every write operations should be called before subsequent read operation.