[concurrency-interest] Is Reference.reachabilityFence() needed in Reference constructor?
Aleksey Shipilev
aleksey.shipilev at oracle.com
Wed Oct 21 15:44:36 UTC 2015
Hi,
On 10/21/2015 03:34 PM, Peter Levart wrote:
> Say it is being used like that:
>
> ReferenceQueue<Object> queue = ...;
>
> WeakReference<Object> wr = new WeakReference(new Object(), queue);
>
> Is it possible that the newly constructed Object is found
> weakly-reachable before the 'queue' is assigned to the Reference.queue
> field or is there something in the JVM that prevents this happening
> (like all the constructor parameters are reachable at least until the
> constructor is finished)?
I think this is largely dependent on VM implementation. IIRC, Hotspot
does not treat constructors differently from regular methods w.r.t.
reachability analysis.
But, I suppose when you are storing the incoming argument in the
instance field, then a story gets simpler, since you now "switch" the
reachability via the argument (which is obviously alive up to the last
use) for the reachability via $this itself.
The Reference case is a bit special here. If we were to store the
referent in the "ordinary" instance, then we are changing one strong ref
for another strong one. But for Reference, we are changing strong ref
for a weak ref, and so we need to make sure there is a strong ref until
the end of the method, with reachabilityFence.
In other words, this seems to be needed, but only for Reference.referent:
> Might the following be needed or not:
>
> Reference(T referent, ReferenceQueue<? super T> queue) {
> this.referent = referent;
> this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
> reachabilityFence(referent);
> }
Of course, this does not tell another (scary) part of the story, what if
the Reference itself is not discovered as strong ref by GC, e.g. when it
isn't published on heap, or scalarized by compiler, etc.
reachabilityFence, as currently implemented, extends the "liveness"
scope of the local variable, but does not convey anything special to the
GC/runtime otherwise.
Thanks,
-Aleksey
P.S. Tried to reproduce the failure in jcstress case to no avail. Maybe
somebody else is more lucky:
@JCStressTest
@Outcome(id = "[true]", expect = Expect.ACCEPTABLE, desc = "TBD")
@State
public class ReferenceNew {
final ReferenceQueue<Object> refq = new ReferenceQueue<>();
WeakReference<Object> wr;
@Actor
public void producer() {
wr = new WeakReference<>(new Object(), refq);
}
@Actor
public void consumer(BooleanResult1 r) {
try {
for (int c = 0; c < 10; c++) {
Reference<?> ref = refq.remove(100);
if (ref != null) {
r.r1 = true;
return;
}
}
r.r1 = false;
} catch (Throwable e) {
r.r1 = false;
}
}
static {
Executors.newScheduledThreadPool(1, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}).scheduleAtFixedRate(
System::gc, 10L, 10L, TimeUnit.MILLISECONDS
);
}
}
More information about the core-libs-dev
mailing list