2828import java .io .FilterOutputStream ;
2929import java .io .IOException ;
3030import java .io .OutputStream ;
31+ import java .lang .ref .PhantomReference ;
3132import java .lang .ref .Reference ;
33+ import java .lang .ref .ReferenceQueue ;
3234import java .lang .ref .WeakReference ;
3335import java .util .concurrent .TimeUnit ;
3436import java .util .logging .Level ;
@@ -65,6 +67,7 @@ private Tuning() {}
6567 super (new FlushControlledOutputStream (out ), tuning .bufferSize );
6668 this .tuning = tuning ;
6769 recurrencePeriod = tuning .minRecurrencePeriod ;
70+ FlushRef .register (this , out );
6871 reschedule ();
6972 }
7073
@@ -95,14 +98,6 @@ void flushAndReschedule() {
9598 reschedule ();
9699 }
97100
98- @ SuppressWarnings ("FinalizeDeclaration" ) // not ideal, but PhantomReference is more of a hassle
99- @ Override protected void finalize () throws Throwable {
100- super .finalize ();
101- Thread .sleep (100 ); // TODO for FileLogStorageTest#remoting
102- // Odd that this is not the default behavior for BufferedOutputStream.
103- flush ();
104- }
105-
106101 private static final class Flush implements Runnable {
107102
108103 /** Since there is no explicit close event, just keep flushing periodically until the stream is collected. */
@@ -121,6 +116,46 @@ private static final class Flush implements Runnable {
121116
122117 }
123118
119+ //
120+ /**
121+ * Flushes streams prior to garbage collection.
122+ * TODO Java 9+ could use java.util.Cleaner
123+ */
124+ private static final class FlushRef extends PhantomReference <DelayBufferedOutputStream > {
125+
126+ private static final ReferenceQueue <DelayBufferedOutputStream > rq = new ReferenceQueue <>();
127+
128+ static {
129+ Timer .get ().scheduleWithFixedDelay (() -> {
130+ while (true ) {
131+ FlushRef ref = (FlushRef ) rq .poll ();
132+ if (ref == null ) {
133+ break ;
134+ }
135+ LOGGER .log (Level .FINE , "cleaning up phantom {0}" , ref .out );
136+ try {
137+ // Odd that this is not the default behavior for BufferedOutputStream.
138+ ref .out .flush ();
139+ } catch (IOException x ) {
140+ LOGGER .log (Level .WARNING , null , x );
141+ }
142+ }
143+ }, 0 , 10 , TimeUnit .SECONDS );
144+ }
145+
146+ static void register (DelayBufferedOutputStream dbos , OutputStream out ) {
147+ new FlushRef (dbos , out , rq ).enqueue ();
148+ }
149+
150+ private final OutputStream out ;
151+
152+ private FlushRef (DelayBufferedOutputStream dbos , OutputStream out , ReferenceQueue <DelayBufferedOutputStream > rq ) {
153+ super (dbos , rq );
154+ this .out = out ;
155+ }
156+
157+ }
158+
124159 /** @see DelayBufferedOutputStream#flushBuffer */
125160 private static final class FlushControlledOutputStream extends FilterOutputStream {
126161
0 commit comments