Is reference update thread safe?

后端 未结 6 514
野趣味
野趣味 2021-01-26 13:49
public class Test{
   private MyObj myobj = new MyObj(); //it is not volatile


   public class Updater extends Thred{
      myobje = getNewObjFromDb() ; //not am settin         


        
相关标签:
6条回答
  • 2021-01-26 13:57

    You may get a stale reference. You may not get an invalid reference. The reference you get is the value of the reference to an object that the variable points to or pointed to or will point to.

    Note that there are no guarantees how much stale the reference may be, but it's still a reference to some object and that object still exists. In other words, writing a reference is atomic (nothing can happen during the write) but not synchronized (it is subject to instruction reordering, thread-local cache et al.).

    If you declare the reference as volatile, you create a synchronization point around the variable. Simply speaking, that means that all cache of the accessing thread is flushed (writes are written and reads are forgotten).

    The only types that don't get atomic reads/writes are long and double because they are larger than 32-bits on 32-bit machines.

    0 讨论(0)
  • 2021-01-26 14:01

    If MyObj is immutable (all fields are final), you don't need volatile.

    0 讨论(0)
  • 2021-01-26 14:02

    No, this is not thread safe. (What makes you think it is?)

    If you are updating a variable in one thread and reading it from another, you must establish a happens-before relationship between the write and the subsequent read.

    In short, this basically means making both the read and write synchronized (on the same monitor), or making the reference volatile.

    Without that, there are no guarantees that the reading thread will see the update - and it wouldn't even be as simple as "well, it would either see the old value or the new value". Your reader threads could see some very odd behaviour with the data corruption that would ensue. Look at how lack of synchronization can cause infinite loops, for example (the comments to that article, especially Brian Goetz', are well worth reading):

    The moral of the story: whenever mutable data is shared across threads, if you don’t use synchronization properly (which means using a common lock to guard every access to the shared variables, read or write), your program is broken, and broken in ways you probably can’t even enumerate.

    0 讨论(0)
  • 2021-01-26 14:02

    The big problem with this sort of code is the lazy initialization. Without volatile or synchronized keywords, you could assign a new value to myobj that had not been fully initialized. The Java memory model allows for part of an object construction to be executed after the object constructor has returned. This re-ordering of memory operations is why the memory-barrier is so critical in multi-threaded situations.

    Without a memory-barrier limitation, there is no happens-before guarantee so you do not know if the MyObj has been fully constructed. This means that another thread could be using a partially initialized object with unexpected results.

    Here are some more details around constructor synchronization:

    Constructor synchronization in Java

    0 讨论(0)
  • 2021-01-26 14:15

    Volatile would work for boolean variables but not for references. Myobj seems to perform like a cached object it could work with an AtomicReference. Since your code extracts the value from the DB I'll let the code stay as is and add the AtomicReference to it.

    import java.util.concurrent.atomic.AtomicReference;
    
        public class AtomicReferenceTest {
            private AtomicReference<MyObj> myobj = new AtomicReference<MyObj>();
    
            public class Updater extends Thread {
    
                public void run() {
                    MyObj newMyobj = getNewObjFromDb();
                    updateMyObj(newMyobj);
                }
    
                public void updateMyObj(MyObj newMyobj) {
                    myobj.compareAndSet(myobj.get(), newMyobj);
                }
    
                 }
            public MyObj getData() {
                 return myobj.get();
            }
        }
    
        class MyObj {
        }
    
    0 讨论(0)
  • 2021-01-26 14:24

    No, it isn't.

    Without volatile, calling getData() from a different thread may return a stale cached value.
    volatile forces assignments from one thread to be visible on all other threads immediately.

    Note that if the object itself is not immutable, you are likely to have other problems.

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