Art Java concurrent programming (9) final

Read and write final field is more like an ordinary variable access

Final rule reordering domain

For the final domain, compilers and processors to comply with two reorder rules.
(1) is written in the constructor of a final field, and then this configuration the referenced object is assigned to a reference variable, the reordering is not between these two operations.
(2) reading a first target domain comprising a final reference, and then read the final initial field, the reordering is not between these two operations.
Examples

public class FinalExample {
    int i;普通变量
    final int j;final变量
    static FinalExample obj;
    public FinalExample() {  构造函数 
        i = 1;  写普通域 
        j = 2;final}
    public static void writer() {  写线程A执行 
        obj = new FinalExample();
    }
    public static void reader() {  读线程B执行 
        FinalExample object = obj;  读对象引用 
        int a = object.i;  读普通域 
        int b = object.j;final}
}

Suppose a writer thread A executes () method, followed by another thread B executed Reader () method.

Write reordering rules final domain

Written final field reordering rules prohibit write reordering final field outside the constructor.
(1) JMM prevent the compiler to write reorder final fields outside constructor.
(2) Before the compiler will write after final field, the constructor return, insert a StoreStore barrier. This barrier is prohibited processor to write reordering final field outside the constructor.
writer () method
(1) to construct an object of a type FinalExample.
(2) The assignment by reference to the object reference variable obj.
Written final field reordering rules to ensure that :
a reference to any thread before seen, final domain object has been initialized correctly over the object.
This domain does not have the ordinary security thread B "see" when the object reference obj, probably not yet been constructed object obj (i write of the regular domain are reordered outside constructor, when the initial value of a further Common domains not written i)
Here Insert Picture Description

Read the final rule reordering domain

Reordering the read field final rule, in a thread, it is first read reference Sion final reading of the first domain and the object contains, JMM prohibition processor reordering these two operations. LoadLoad compiler inserts a barrier in front of the final read-domain operations.
First reading and the initial reading final object reference field contains the object, an indirect dependency between the two operations. Since the compiler compliance indirect dependencies, the compiler does a reordering of these two operations.
Reder () method includes three operations
(1) initial read reference variable obj
(2) initial read reference variable obj pointing object ordinary domain J
(. 3) first read reference variable obj pointing object final fields i
assumed writer thread A has not occurred any re-ordering, and the program execution does not comply indirectly dependent on processor
Here Insert Picture Description
operations to read ordinary domain object is reordered before the processor to read the object reference. Reading is a common domain, the domain has not been written thread A written, this is a wrong read operation. While the final read operation field rules will read reorder final target domain "defined" After reading object reference, at which time the final thread A domain has been initialized, and this is a proper reading operation
to read the final field reordering rules ensure: before the final reading of an object domain, we will first read the final field contains an object reference. In this example, if the reference is not null, then the object reference final domain must have been initialized A thread before.

final field is a reference type

public class FinalReferenceExample {
    final int[] intArray;  final是引用类型
    static FinalReferenceExample obj;
    public FinalReferenceExample() {  构造函数
        intArray = new int[1];        1 
        intArray[0] = 1;              2 
    }
    public static void writerOne() {  写线程A执行 
        obj = new FinalReferenceExample();   3 
    }
    public static void writerTwo() {   写线程B执行 
        obj.intArray[0] = 2;                 4
    }
    public static void reader() {  读线程C执行 
        if (obj != null) {                   5
            int temp1 = obj.intArray[0];     6 
        }
    }
}

For reference types, the write field final reordering rules compiler and processor adds the following constraint:
writing member of a domain in the constructor for a final reference object, and this is then configured outside the object constructor a reference to a reference assigned to a variable, you can not reorder operation between the two
JMM ensures that the reader thread could see at least write C a thread in the constructor written to members of the domain object reference to the final.
I.e. 0 C to see at least in the array is labeled 1. The writer thread B might see the writing array elements, read thread C, could not see.
JMM is not guaranteed to read the writing thread B thread C visible because there is competition between data read and write thread B thread C, at this time the results are unpredictable.
If you want to make sure that read write thread B thread C see the array elements to write, write, requires the use of synchronization primitives (lock or volatile) between threads B and C to ensure that the memory read threads visibility.

You can not escape from the final reference constructor

Written final field reordering rules to ensure that: before any thread can be seen in reference variables as the reference point of the final object variable domain has been correctly initialized in the constructor. To get this effect, you also need a guarantee: Inside the constructor, jumped in to make this structured object reference for the other threads can see, that is no longer the object reference constructor escape.

public class FinalReferenceEscapeExample {
    final int i;
    static FinalReferenceEscapeExample obj;
    public FinalReferenceEscapeExample() {
        i = 1;            1final域 
        obj = this;       2 this引用在此"逸出" 
    }

    public static void writer() {
        new FinalReferenceEscapeExample();
    }

    public static void reader() {
        if (obj != null) {      3 
            int temp = obj.i;   4 
        }
    }
}

Here Insert Picture Description
Suppose a thread A executes wirter () method, another thread B executed Reader () method. 2 so that the operation object is here configured as a visible before thread B has not been completed. 2 even if the operation here is the final step of the constructor, and the operation thread in 2 rows behind the method of operation 1, perform read () you can not see the pit still be initialized values of final fields in the program, because the operation here and 1 operation may be reordered between 2
Here Insert Picture Description
before the constructor returns the referenced object is not seen for other threads configured, the final because the domain has not been initialized. After the constructor returns, any thread will be guaranteed to see the value after the final field initialized correctly.

JSR-133 enhanced the semantic final

In the old Java memory model, one of the most serious flaw is the thread may see the value of final fields will change.
For instance, when a thread is currently seeing an integer final field is set to 0 (the default value has not been initialized before), after a period of time to go read this thread final value of this field, but found the value to 1 (the a thread value after initialization).
The most common example is the old Java memory model, the value of String may change.
To fix this vulnerability, JSR-133 expert group enhances the semantic final.
By increasing the field for the final read-write and re-ordering rules, initialization can provide security for Java programmers: As long as the object is properly constructed in (cited no "escape" in the constructor constructed object), you do not need to use synchronous value (refers to the use of lock and volatile) can ensure that any thread can see the final field is initialized in the constructor after

Published 24 original articles · won praise 1 · views 543

Guess you like

Origin blog.csdn.net/qq_45366515/article/details/105146305