I am familiar with the synchronized
block/method. Is this required when modifying fields from separate threads? Will setting and getting the field without synchronization at the same time cause the field to get screwed up? Here is a little graph:
Time | Thread A | Thread B
1 ... ...
2 fieldA = 10; System.out.println(fieldA);
3 fieldA = 20; fieldA = 30;
4 ... ...
Could something like this cause some sort of exception and multi-threaded fields should always be accessed through synchronization? Could this behavior change when using objects vs. primitives as a field type?
Reading this, it convinces me that two threads have different memory and each field change is cloned to all the other threads "sharing" this field.
Could bytecode instructions be executed in strange ways? Like say the bytecode to do ++
was getting the value, incrementing the value, and storing it.
Time | Thread A | Thread B //Imagine in bytecode
1 x = 10 waiting
2 y = x + 1 waiting
3 waiting x = 0;
4 waiting ...
5 x = y waiting
In the above example, Thread A incremented x from 10 to 11, but Thread B's x = 0 was completely ignored. If this type of thread switching didn't happen and it was done on a statment-by-statement basis, then the result of the two threads work would result either 0, or 1.
So again, my question is, when is synchronization required when modifying shared fields? If synchronization is required or not, can you please explain why and include the few examples above?
Yes -- this is pretty much a textbook example of things you have to synchronize.
If you want to get into the JLS, chapter 17 has all the relevant stuff. Some excerpts:
Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.
...
When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race.
...
A set of actions is sequentially consistent if all actions occur in a total order (the execution order) that is consistent with program order
...
If a program has no data races, then all executions of the program will appear to be sequentially consistent.
In other words:
It's even weirder than the cases you provide. You can have code a = 10; b = 20;
, and one thread will see execution in that order, while another thread sees b = 20; a = 10;
. This happens due to optimizer reorderings, memory caches, and any number of optimizations that make your multi-core machine go fast, but at the cost of confusing multi-threaded behavior.