Finalizers run in a dedicated finalizer thread and what you have written is thread-unsafe code. Use a synchronized collection, for example.
The other pitfall is, just calling System.gc()
is no guarantee that the finalizer has run by the time that method call returns. The finalizer has merely been enqueued in the finalizer thread's queue—if even that. To work around this you should really use a synchronization helper such as CountDownLatch
and call System.gc()
two or three times, for good measure.
Here, your code improved with the above ideas:
public class Stuff {
static final List<Stuff> list = Collections.synchronizedList(new ArrayList<Stuff>());
static final CountDownLatch cdl = new CountDownLatch(1);
@Override protected void finalize() {
list.add(this);
cdl.countDown();
}
public static void main(String[] args) throws Exception {
list.add(new Stuff());
list.remove(0);
System.gc();
System.gc();
cdl.await();
System.out.println(list.size());
}
}