[concurrency-interest] Thread safety of WeakReference .get() method?

Aleksey Shipilev aleksey.shipilev at oracle.com
Wed Aug 8 04:58:12 EDT 2012


Interesting. I would agree with that non-volatile reads as the condition
to exit the busy loop are particularly nasty.

I also tend to think "volatile" is much too strict for this use case,
because it will introduce unnecessary memory ordering. In the absence of
explicit barriers, this seems to be the work for non-yet-existing
Unsafe.getOrderedObject(), which should just require VM to omit
speculative reads and re-read memory on every get().

-Aleksey.

On 08/08/2012 12:24 PM, Dr Heinz M. Kabutz wrote:
> Looks like common sense has yet again not prevailed.  In this little
> test, I am calling WeakReference.get() in a tight loop from one thread,
> called "readerThread".  Since the "referent" field inside the
> WeakReference is not volatile and there is no synchronization at all for
> that field, the "readerThread" eventually inlines the method call to
> get() and caches the value of the "referent" field.  The "queueReader"
> thread calls "remove()" from the ReferenceQueue and wakes up pretty
> quickly after we have set the field "str" to null and invoked
> System.gc().  Interestingly, The Object is finalized even though the
> readerThread still has a reference to it!
> 
> If you run this with the -server flag, the program will not finish. 
> With -client it finishes, because it does not cache the referent field
> value in the readerThread.
> 
> import java.lang.ref.*;
> 
> public class WeakReferenceTest {
>   private static Object str = new Object() {
>     public String toString() {
>       return "The Object";
>     }
> 
>     protected void finalize() throws Throwable {
>       System.out.println("The Object is being finalized");
>       super.finalize();
>     }
>   };
>   private final static ReferenceQueue<Object> rq =
>       new ReferenceQueue<Object>();
>   private final static WeakReference<Object> wr =
>       new WeakReference<Object>(str, rq);
> 
>   public static void main(String[] args)
>       throws InterruptedException {
>     Thread reader = new Thread() {
>       public void run() {
>         while (wr.get() != null) {
>         }
>         System.out.println("wr.get() returned null");
>       }
>     };
> 
>     Thread queueReader = new Thread() {
>       public void run() {
>         try {
>           Reference<? extends Object> ref = rq.remove();
>           System.out.println(ref);
>           System.out.println("queueReader returned, ref==wr is "
>               + (ref == wr));
>         } catch (InterruptedException e) {
>           System.err.println("Sleep interrupted - exiting");
>         }
>       }
>     };
> 
>     reader.start();
>     queueReader.start();
> 
>     Thread.sleep(1000);
>     str = null;
>     System.gc();
>   }
> }
> 
> 
> Output with Server HotSpot:
> 
> The Object is being finalized
> java.lang.ref.WeakReference at 72ebbf5c
> queueReader returned, ref==wr is true
>  -- VM does not end
> 
> 
> Output with Client HotSpot:
> 
> The Object is being finalized
> wr.get() returned null
> java.lang.ref.WeakReference at 110769b
> queueReader returned, ref==wr is true
> 
> 
> Conclusion:
> 
> The "referent" field in java.lang.ref.Reference should probably be
> marked as "volatile".
> 
> Regards
> 
> Heinz
> -- 
> Dr Heinz M. Kabutz (PhD CompSci)
> Author of "The Java(tm) Specialists' Newsletter"
> Sun Java Champion
> IEEE Certified Software Development Professional
> http://www.javaspecialists.eu
> Tel: +30 69 75 595 262
> Skype: kabutz 
> 
> 
> 
> On 8/7/12 4:49 PM, Aleksey Shipilev wrote:
>> On 08/07/2012 04:47 PM, Raph Frank wrote:
>>
>>   
>>> The documentation says that once an object has been determined to be
>>> garbage collectable, "At that time it will atomically clear all weak
>>> references to that object", so presumably, the get method can be
>>> called, some if is atomically set to null?
>>>     
>> I think the real meaning behind that claim is "atomically set *all* weak
>> references to that object", i.e. two weak references to the same object
>> will simultaneously become clear once object is not reachable.
>>
>> Mutator threads are not modifying the referent, and so the real question
>> should be: is it possible to read the non-null referent after weak
>> reference is cleared? There is no difference how many user threads are
>> accessing now, because the possible race is between mutator threads and GC.
>>
>> The answer to that is VM-specific. Common sense is that all GC
>> operations should be committed before returning back to the mutator
>> after stop-the-world, or notified to the mutator as soon as possible in
>> concurrent GCs. If that wasn't true, WeakRefs would risk keep
>> referencing the objects that are not really there, and it would broke
>> too many applications already.
>>
>> -Aleksey.
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>   



More information about the Concurrency-interest mailing list