|
JDK5 introduced the new JMM specification: JSR-133, introduced the concept of happen-before / visibility, such as synchronized / volatile / final keywords such as the semantic definition. Resolved: Final variables thread initialization in the constructor of the safety and volatile variables and no-volatile variables between the reordering problem.
Why Memory Model
In a multi-threaded scene, thread1 to modify a variable, thread2 to read this variable, which may occur during the order of the implementation of the problem (because the compiler optimization instruction, the processor reorder instruction, write data cache is not updated to Main memory). How to ensure that the variable is to read the thread2 Thread1 want to amend the variables?
Memory Model describes the variables in the program and their relationship in registers, cache, and memory. That is, in the absence of Momory Model, can not guarantee the multithreading environment variable call order, with the Memory Model specific keywords corresponding to the semantic definition (such as the synchronized / volatile / final), you can use these keywords Ensure that the program is in accordance with the desired logic in a multi-threaded environment to the correct implementation.
Old JMM problem
Issue # 1: Immutable Objects are not immutable
Immutable objects: All fields of an object must be final, and must be a primitive type or a reference to an immutable object. For example, the String object is immutable and semantically should not require synchronization, but the fact is that there may be competing conditions in a multithreaded scenario.
@ JKD1.4
Class String
{
Static final char [] charArray;
Static int length;
Static int offset; / / that the beginning of the string position
}}
CharArray array and length, offset can be shared in multiple String / StringBuffer. For example String.substring () is to share the original String charArray.
String s1 = "/ usr / tmp";
String s2 = s1.substring (4); // contains "/ tmp"
In the old JMM, there is no synchronization. Initialize s1, the object constructor will length / offset initialized to 0, this time other threads can access these values (this time using substring obvious problem), then the String constructor for the length / offset assignment as needed value. The new JMM model solves the thread-safety problem of finalizing a final variable in the constructor, which means that the final variable is not allowed to be visible to other threads until it is initialized (before the constructor completes execution).
Issue # 2: Re-ordering volatile and non-volatile variables
Volatile variables in the old JMM only one semantics: For a volatile variable read, can always see the other arbitrary thread on the volatile variables of the last write. That is, writes to volatile variables are happends-before other threads read them.
In the old JMM, although reordering between volatile variables is not allowed, the reordering of volatile variables with other normal variables is allowed. This causes a problem in scenarios where volatile variables are flagged.
Map configOptions;
Char [] configText;
Volatile boolean initialized = false;
.
// In thread A
ConfigOptions = new HashMap ();
ConfigText = readConfigFile (fileName);
ProcessConfigOptions (configText, configOptions);
Initialized = true;
.
// In thread B
While (! Initialized)
Sleep ();
// use configOptions, in the old JMM, there is no guarantee that configOptions have been initialized, because the order of variables may have been rearranged.
The new JMM model solves this problem by introducing a new semantics: volatile variables can not be rearranged with non-volatile variables.
The new JMM
Visibility
When ThreadA implementation val = 1, other threads can see how to ensure that the implementation of ThreadA results (that variable at this time on the other thread Visibility)? JMM specification of certain definitions (volatile / synchronized / final) to ensure that this matter.
Synchronization and Visibility
Synchronization not only has access to a critical area lock semantics, but also has the memory visibility (memory visibility) significance. When you leave the synchronized block, the cache must flush to main memory. When you enter the synchronized block, the cache is invalid, and subsequent read operations must be read to main memory. That is, the variables inside the synchronized block write operation is visible to other threads (visible)!
Volatile
The new JMM enhances the memory semantics of volatile and prohibits rearrangement with normal variables. That is, threadA writes to a volatile variable, threadB reads that variable. Then all the variables visible to A must be visible to B at the same time.
Happens-before
Ordinary multithreading If there is no data sharing and interaction, the instructions may be reordered for optimization reasons, will not be affected. If there is data between the competing threads, you need to use synchronized (Moniter) / volatile, etc. to ensure that the order of the implementation of the order. JMM defines a sort called "happens-before", which uses the concept of JMM to explain what memory visibility is. If the result of one operation A is visible to the other operation B, then A happends-before B.
* A thread in front of the operation happends-before the next operation.
* On the monitor unlock happends-before follow-up of the lock operation.
* Write to the volatile variable happends-before subsequent reads.
* Thread.start () calls the operation happends-before thread-internal operations.
* All operations of the thread are happends-before the subsequent thread join ().
Data races - data competition
There is data competition, indicating that the program did not make good synchronization, did not handle the happends-before relationship.
Initialization of the final variable security
Objects are only visible to other threads after their initial initialization. This means that initialization of the final variable can be thread-safe without the use of synchronization. In this way, the final variable to achieve the true sense of the final (that is, not - can - change), and not in the initialization process, the multithreading appears to change.
Class A
{
Final Map < String, String> map = null;
Public void A ()
{
Map = new HashMap < String, String> ();
Map.put ( "key1", "value1");
}}
}}
Other threads Before referencing an object, JMM guarantees that A's final variable has been fully initialized by its constructor. That is, the final initialization of the variable happends-before other threads reference the object. That is, the initialization of the final variable in the constructor is thread-safe. |
|
|
|