< 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 >