Can I assume 'no data race' between user thread and finalize thread in Java

235 views Asked by At

Consider the following Java class:

class X {
    public void foo() {
        bar = 1;
    }

    protected void finalize() {
        if (bar == 1)
            baz();
    }

    private int bar = 0;
}

Under the assumption that X.foo() is never called from any finalize() method (directly or indirectly), can I be sure that the code above is free of data-races, that is, can I be sure that X.finalize() sees the value written by X.foo() in every case where X.foo() is actually called?

The naive analysis would say that X.finalize() cannot run concurrently with X.foo() (due to the mentioned assumption), so no extra synchronization is necessary.

I would guess that the code above is free of data races, but it troubles me that the language specification contains the following explicit statement in §17.4.5, but says nothing about a happens-before relationship between finalize() and methods in general:

There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object.

EDIT: I see the need to make my question more precise, so here is an attempt at a precise reformulation of the question:

Does Java guarantee a happens-before relation between a specific method X.foo() and X.finalize() if I guarantee that X.foo() is never called (directly or indirectly) from any finalize() method? Here, happens-before is to be interpreted exactly as defined in §17.4.5.

3

There are 3 answers

9
peter.petrov On

Setting/Getting an int value in Java is atomic anyway AFAIK.

So I don't think you should worry.

"but says nothing about a happens-before relationship
between finalize() and methods in general"

That's because those methods (in general) are not managed/called
by the JVM but by you. So it cannot say anything.

By the way if app code can still call foo(), it means this app
code has reference to your object so your object is not eligible
for garbage collection (i.e. for finalize() to be called).
So, you know, I doubt your concern has grounds at all.

UPDATE:

"Does Java guarantee a happens-before relation between a specific method X.foo() and
X.finalize() if I guarantee that X.foo() is never called (directly or indirectly) from
any finalize() method"

Assume the opposite -> Imagine the situation you get.

The finalize() method was called on object x; then somebody calls foo() on this object x (note: x is already dead i.e. garbage collected) object. Does that sound possible? Not to me.

2
Chriss On

Since every Thread have an cache of variables it is not thread safe, in other works every thread have its own view of variables. You can apply volatine to the variable to force the Thread load the variable. The same works if the variable is accessed from a synchronized block

-> When does java thread cache refresh happens?

0
Thomas Krieger On

No. You do not have a happen before relationship between foo() and finalize(). This basically means that you might see zero in the method finalize() for the field bar.

I think the java memory model basically says that each thread runs on it own and sees the actions of the other threads in undefined and therefore platform dependent order. Only through the use of the actions described under Happens Before you achieve a defined order.

In your case the finalize() method might not see the value 1 written in the foo method running in a different thread. One reason for this could be, that the two thread run on different cpu cores, which use a memory cache.

Since bugs like this are so hard to find, I developed a tool called vmlens, which detects race conditions using an algorithm called eraser