Concurrency and high concurrency (XI) - Object security release

Foreword

What is the target release it? Briefly, the object is to make our definition can be used outside the scope of other ranges.

Body outline

  • Release and escape of an object
  • Four ways to target security release

Main content

First, release and escape of an object

1. Concept

Post Object: make an object can be used by code outside the current range.

Object escape: a false release. When an object has not been completed structure, it will be seen in other threads.

2. Usually we will return objects by non-private methods or classes of references to publish public static variable objects. Next, look at the examples cited unsafe release of non-private method returns an object.

 

@ SLF4J
 public  class UnsafePublish {
     Private String [] States = { " A " , " B " , " C " }; 
    
    public String [] the getStates () {
         return States; 
    } 
    
    public  static  void main (String [] args) { 
        UnsafePublish up = new new UnsafePublish (); 
        log.info ( " States: {} " , of Arrays.toString (up.getStates ()));
         // it an array of private property modification 
        up.getStates () [ 0]="d";
        log.info("states:{}",Arrays.toString(up.getStates()));

    }
}

 

Such a result would be:

23:19:37.949 [main] INFO com.controller.publish.UnsafePublish - states:[a, b, c]
23:19:37.952 [main] INFO com.controller.publish.UnsafePublish - states:[d, b, c]

Example is very simple, but still look at, because the non-private methods (public access level), the external thread class can access this field, so the release of the object is actually unsafe, because we can not guarantee that other threads will not modify this field, resulting in states inside the class of error.

3. Next, introduce escape release about the subject, to show an example.

@Slf4j
public class Escape {
    private int thisCanbeEscape=0;
    
    public Escape(){
        new InnerClass();
    }
    //定义一个内部类
    private class InnerClass{
        public InnerClass(){
            log.info("{}",Escape.this.thisCanbeEscape);
        }
    }
    public static void main(String[] args){
        new Escape();
    }
}

result:

23:35:56.093 [main] INFO com.controller.publish.Escape - 0

Internal code look class instance which contains a reference to the instance of the package, this may lead to Escape object is not completed will be released fully configured, may cause problems.

Specific explanation: In the constructor's Escape is equivalent to starting a thread, which can cause escape, a new thread inside the class constructor of this reference will always be able to see your subject before construction is completed this is a reference to .

Second, the safe release of four methods object

  • Initialize an object in a static initialization function references
  • The reference to stored object volatiletype field or AtomicReferenceobject
  • The object reference saved to a properly constructed object  finaltype field
  • Save the object reference to a domain protected by a lock

This is how the four methods to understand it, by the following four examples to explain it.

1. First, we passed a singleton design pattern code (lazy man) look at the kind of problems that occur in multithreaded scenarios.

public  class the Singleton {
     // private constructor 
    Private the Singleton () { 

    } 
    // singleton object 
    Private  static the Singleton instance = null ;
     // static factory method 
    public  static the Singleton the getInstance () {
         IF (instance == null ) { 
            instance = new new the Singleton (); 
        } 
        return instance; 
    } 
}

The above observation code, no problem at single-threaded, multi-threaded under so, when a judge after two threads instance == null condition is satisfied, into the process of creating an object, then the private constructor is equivalent to calling on both sides If the constructor is private operation of subtraction value, this value is not it will be plus or minus two, it must be incorrect. The above code is thread safe.

2. lazy singleton seen, look at the following singleton hungry man style.

public  class Singleton2 {
     // private constructor 
        Private Singleton2 () { 

        } 
        // singleton object 
        Private  static Singleton2 instance = new new Singleton2 ();
         // static factory method 
        public  static Singleton2 the getInstance () {
             return instance; 
        } 
}

Anyway, hungry man will directly create class object type, regardless of whether the object is used, it will be created, which leads to performance problems, resulting in waste of resources. Therefore, when we use a hungry man style, we must consider whether it is private constructor excessive processing logic.

To sum up the two examples, although hungry Chinese-style thread-safe, but it is likely to cause performance problems, then the lazy man can not be transformed into a thread-safe? The answer is yes. Let's look at how to transform it!

Guess what, if you can guarantee method to create the object would not only be caused by a thread to access thread-safe, so adding synchronized on a static factory method

// static factory method 
        public the synchronized static Singleton3 the getInstance () {
             IF (instance == null ) { 
                instance = new new Singleton3 (); 
            } 
            return instance; 
        }

While this ensures thread safety, but it resulted in a performance cost, so such an approach is not recommended! ! !

That if we will sink synchronized to create objects?

public  class Singleton4 {
     // private constructor 
            Private Singleton4 () { 

            } 
            // singleton object 
            Private  static Singleton4 instance = null ;
             // static factory method 
            public  static Singleton4 the getInstance () {
                 IF (instance == null ) { 
                    the synchronized ( Singleton4. class ) {
                         IF (instance == null ) {// double detection mechanism 
                            instance = new new  Singleton4 ();
                        }
                    }
                }
                return instance;
            }
}

In fact, this approach has become a thread unsafe. Here's review process objects created, (1) memory = allocate () object's memory space allocated (2) ctorInstance () to initialize the object (3) instance = memory settings instance just point to memory allocation. Here JVM instructions and CPU rearrangement occurs (refer to the instruction concurrently with the rearrangement high concurrency (X)), which results in the above three steps are not performed according to the above procedure, but became (1) ( 3) (2) in this order. This scenario occurs requires explanation: As shown in the code, on the premise of the instruction rearrangement, when the thread A, B each thread to execute the code in the location identified, A begins execution of step (3), then when the judgment execution thread B, found value, and will direct return instance. The actual thread A (2) do not step initialize the object. Although the probability of this problem is very small, but this method is still not thread-safe.

public  class Singleton4 {
     // private constructor 
            Private Singleton4 () { 

            } 
            // singleton object 
            Private  static Singleton4 instance = null ;
             // static factory method 
            public  static Singleton4 the getInstance () {
                 IF (instance == null ) {// thread B 
                    the synchronized (Singleton4. class ) {
                         IF (instance == null ) { // double detection mechanism 
                            instance = new new Singleton4 (); // thread A-3
                        }
                    }
                }
                return instance;
            }
}

Since it is a problem because of the instruction rearrangement leads, then we will not let happen JVM and CPU instruction rearrangement.

Before a keyword learned to think of it: volatile. Based on the above code based on the added volatile singleton object declaration.

private volatile static Singleton4 instance = null;

So the lazy man becomes a singleton thread safe.

There must certainly remember, because usually write the code can easily be overlooked. This is one of volatile usage scenarios: volatile + = double detection prohibiting command reordering mechanism.

3. Also mentioned in a thread-safe, reliable enumeration mode:

public  class Singleton5 {
     Private Singleton5 () { 
        
    } 
    public  static Singleton5 the getInstance () {
         return Singleton.INSTANCE.getInstance (); 
    } 
    Private  enum the Singleton { 
        INSTANCE; 
        
        Private Singleton5 Singleton;
         // the JVM absolute guarantee that this method is called once 
        the Singleton ( ) { 
            Singleton = new new Singleton5 (); 
        } 
        
        public Singleton5 the getInstance () {
             return Singleton; 
        } 
    } 
}

Guess you like

Origin www.cnblogs.com/jmy520/p/12078856.html