Creating Object in a thread safety way

前端 未结 8 2237
再見小時候
再見小時候 2021-02-06 12:50

Directly from this web site, I came across the following description about creating object thread safety.

Warning: When constructing an object that will b

相关标签:
8条回答
  • 2021-02-06 13:14

    I think that the following example illustrate what authors wanted to say:

    public clsss MyClass {
        public MyClass(List<?> list) {
            // some stuff 
    
            list.add(this); // self registration
    
            // other stuff 
        }
    }
    

    The MyClass registers itself in list that can be used by other thread. But it runs "other stuff" after the registration. This means that if other thread starts using the object before it finished its constructor the object is probably not fully created yet.

    0 讨论(0)
  • 2021-02-06 13:14

    Its describing the following situation:

    Thread1:
     //we add a reference to this thread
     object.add(thread1Id,this);
     //we start to initialize this thread, but suppose before reaching the next line we switch threads
     this.initialize(); 
    Thread2:     
    //we are able to get th1, but its not initialized properly so its in an invalid state 
    //and hence th1 is not valid
    Object th1 = object.get(thread1Id); 
    
    0 讨论(0)
  • 2021-02-06 13:16
    1. Let us assume, you have such class:

      class Sync {
          public Sync(List<Sync> list) {
              list.add(this);
              // switch
              // instance initialization code
          }
      
          public void bang() { }
      }
      
    2. and you have two threads (thread #1 and thread #2), both of them have a reference the same List<Sync> list instance.

    3. Now thread #1 creates a new Sync instance and as an argument provides a reference to the list instance:

      new Sync(list);
      
    4. While executing line // switch in the Sync constructor there is a context switch and now thread #2 is working.

    5. Thread #2 executes such code:

      for(Sync elem : list)
          elem.bang();
      
    6. Thread #2 calls bang() on the instance created in point 3, but this instance is not ready to be used yet, because the constructor of this instance has not been finished.

    Therefore,

    • you have to be very careful when calling a constructor and passing a reference to the object shared between a few threads
    • when implementing a constructor you have to keep in mind that the provided instance can be shared between a few threads
    0 讨论(0)
  • 2021-02-06 13:23

    Thread A is creating Object A, in the middle of creation object A (in first line of constructor of Object A) there is context switch. Now thread B is working, and thread B can look into object A (he had reference already). However Object A is not yet fully constructed because Thread A don't have time to finish it.

    0 讨论(0)
  • 2021-02-06 13:31

    Here is your clear example :

    Let's say, there is class named House

    class House {
        private static List<House> listOfHouse;
        private name;
        // other properties
    
        public House(){
            listOfHouse.add(this);
            this.name = "dummy house";
            //do other things
        }
    
     // other methods
    
    }
    

    And Village:

    class Village {
    
        public static void printsHouses(){
             for(House house : House.getListOfHouse()){
                   System.out.println(house.getName());
             }
        }
    }
    

    Now if you are creating a House in a thread, "X". And when the executing thread is just finished the bellow line,

    listOfHouse.add(this); 
    

    And the context is switched (already the reference of this object is added in the list listOfHouse, while the object creation is not finished yet) to another thread, "Y" running,

    printsHouses();
    

    in it! then printHouses() will see an object which is still not fully created and this type of inconsistency is known as Leak.

    0 讨论(0)
  • 2021-02-06 13:32

    Lot of good data here but I thought I'd add some more information.

    When constructing an object that will be shared between threads, be very careful that a reference to the object does not "leak" prematurely.

    While you are constructing the object, you need to make sure that there is no way for other threads to access this object before it can be fulling constructed. This means that in a constructor you should not, for example:

    • Assign the object to a static field on the class that is accessible by other threads.
    • Start a thread on the object in the constructor which may start using fields from the object before they are fulling initialized.
    • Publish the object into a collection or via any other mechanisms that allow other threads to see the object before it can be fulling constructed.

    You might be tempted to add the following line to your constructor:

       instances.add(this);
    

    So something like the following is improper:

      public class Foo {
          // multiple threads can use this
          public static List<Foo> instances = new ArrayList<Foo>();
          public Foo() {
             ...
             // this "leaks" this, publishing it to other threads
             instances.add(this);
             ...
             // other initialization stuff
          }
          ...
    

    One addition bit of complexity is that the Java compiler/optimizer has the ability to reorder the instructions inside of the constructor so they happen at a later time. This means that even if you do instances.add(this); as the last line of the constructor, this is not enough to ensure that the constructor really has finished.

    If multiple threads are going to be accessing this published object, it must be synchronized. The only fields you don't need to worry about are final fields which are guaranteed to be finished constructing when the constructor finishes. volatile fields are themselves synchronized so you don't have to worry about them.

    0 讨论(0)
提交回复
热议问题