< prev index next >

src/java.base/share/classes/java/lang/ref/Finalizer.java

Print this page
8197812: (ref) Data race in Finalizer
Reviewed-by: plevart, mchung

*** 34,103 **** final class Finalizer extends FinalReference<Object> { /* Package-private; must be in same package as the Reference class */ private static ReferenceQueue<Object> queue = new ReferenceQueue<>(); private static Finalizer unfinalized = null; private static final Object lock = new Object(); ! private Finalizer ! next = null, ! prev = null; ! private boolean hasBeenFinalized() { ! return (next == this); ! } ! ! private void add() { synchronized (lock) { if (unfinalized != null) { this.next = unfinalized; unfinalized.prev = this; } unfinalized = this; } } - private void remove() { - synchronized (lock) { - if (unfinalized == this) { - if (this.next != null) { - unfinalized = this.next; - } else { - unfinalized = this.prev; - } - } - if (this.next != null) { - this.next.prev = this.prev; - } - if (this.prev != null) { - this.prev.next = this.next; - } - this.next = this; /* Indicates that this has been finalized */ - this.prev = this; - } - } - - private Finalizer(Object finalizee) { - super(finalizee, queue); - add(); - } - static ReferenceQueue<Object> getQueue() { return queue; } /* Invoked by VM */ static void register(Object finalizee) { new Finalizer(finalizee); } ! private void runFinalizer(JavaLangAccess jla) { ! synchronized (this) { ! if (hasBeenFinalized()) return; ! remove(); } try { Object finalizee = this.get(); if (finalizee != null && !(finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee); --- 34,91 ---- final class Finalizer extends FinalReference<Object> { /* Package-private; must be in same package as the Reference class */ private static ReferenceQueue<Object> queue = new ReferenceQueue<>(); + + /** Head of doubly linked list of Finalizers awaiting finalization. */ private static Finalizer unfinalized = null; + + /** Lock guarding access to unfinalized list. */ private static final Object lock = new Object(); ! private Finalizer next, prev; ! private Finalizer(Object finalizee) { ! super(finalizee, queue); ! // push onto unfinalized synchronized (lock) { if (unfinalized != null) { this.next = unfinalized; unfinalized.prev = this; } unfinalized = this; } } static ReferenceQueue<Object> getQueue() { return queue; } /* Invoked by VM */ static void register(Object finalizee) { new Finalizer(finalizee); } ! private void deregisterAndRunFinalizer(JavaLangAccess jla) { ! synchronized (lock) { ! if (this.next == this) // already finalized ! return; ! // unlink from unfinalized ! if (unfinalized == this) ! unfinalized = this.next; ! else ! this.prev.next = this.next; ! if (this.next != null) ! this.next.prev = this.prev; ! this.prev = null; ! this.next = this; // mark as finalized } + runFinalizer(jla); + } + + private void runFinalizer(JavaLangAccess jla) { try { Object finalizee = this.get(); if (finalizee != null && !(finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee);
*** 153,167 **** // in case of recursive call to run() if (running) return; final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); running = true; ! for (;;) { ! Finalizer f = (Finalizer)queue.poll(); ! if (f == null) break; ! f.runFinalizer(jla); ! } } }); } /* Invoked by java.lang.Shutdown */ --- 141,152 ---- // in case of recursive call to run() if (running) return; final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); running = true; ! for (Finalizer f; (f = (Finalizer)queue.poll()) != null; ) ! f.deregisterAndRunFinalizer(jla); } }); } /* Invoked by java.lang.Shutdown */
*** 177,191 **** --- 162,180 ---- if (running) return; final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); running = true; for (;;) { + // "pollFirst" from unfinalized Finalizer f; synchronized (lock) { f = unfinalized; if (f == null) break; unfinalized = f.next; + if (unfinalized != null) + unfinalized.prev = null; + f.next = f; // mark as finalized } f.runFinalizer(jla); }}}); }
*** 212,222 **** final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); running = true; for (;;) { try { Finalizer f = (Finalizer)queue.remove(); ! f.runFinalizer(jla); } catch (InterruptedException x) { // ignore and continue } } } --- 201,211 ---- final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); running = true; for (;;) { try { Finalizer f = (Finalizer)queue.remove(); ! f.deregisterAndRunFinalizer(jla); } catch (InterruptedException x) { // ignore and continue } } }
< prev index next >