2016-06-13 15 views
4

Wenn ichKönnen andere Methoden nach finalize() aufgerufen werden?

public class Foo { 
    private boolean finalized = false; 

    public void foo() { 
     if (finalized) 
      throw new IllegalStateException("finalize() has been called."); 
    } 

    @Override public void finalize() { 
     super.finalize(); 
     finalized = true; 
    } 
} 

Ist es garantiert, selbst im Angesicht von mehreren Threads, nur die GC vorausgesetzt wird finalize() rufen, dass die IllegalStateException nie geworfen werden?

Ich weiß, dass angesichts einer finalize() Methode, die bewirkt, dass das Objekt nicht müllsammelbar ist, das Objekt nicht Müll gesammelt und andere Methoden aufgerufen werden können. Aber das finalize() macht das nicht. Gibt es noch eine Möglichkeit, dass foo() nach finalize() aufgerufen wird?

+1

Haben Sie Fragen bedeuten, ‚nach Finalisierung hat wurde von der GC aufgerufen? Sonst könnte ein Idiot dich explizit ansprechen. – bmargulies

+0

@bmargulies Danke, das ist eigentlich was ich meinte. – Owen

+0

Sie sollten diese Methode so schützen, wie ursprünglich in Objekt nicht öffentlich definiert, um das Risiko zu begrenzen –

Antwort

7

Es ist durchaus möglich, dass ein verschiedene Objekt, das einen Verweis auf die Instanz von Foo hatte bei gleichzeitig abgeschlossen werden - und kann das Foo Objekt wiederzubeleben, so dass es nach der Finalisierung verwendet werden. Das ist ein bisschen unhöflich, kann aber durchaus passieren.

Auch ohne Auferstehung, könnte eine andere Finalizerthread nennen Foo.foo() von seine Finalizerthread:

public class Bar { 
    private final Foo foo; 

    @Override protected void finalize() { 
     // The finalizer in foo may already have executed... 
     foo.foo(); 
    } 
} 
0

Als Jon Skeet erwähnt, ist es durchaus möglich, Methoden aufgerufen werden, während ein Thread in Ihrem Finalisierung ist.

Um dagegen zu schützen, können Sie den Code sicher threadsicher machen.

public class Foo { 
    private boolean finalized = false; 

    public void foo() { 
     synchronized (this) 
     { 
      if (finalized) 
       throw new IllegalStateException("finalize() has been called."); 
     } 
    } 

    @Override public void finalize() { 

     synchronized (this) 
     { 
      super.finalize(); 
      finalized = true; 
     } 
    } 
} 

Hinweis: besonders vorsichtig sein, würde ich den Anruf gestellt super.finalize() in einem try/finally-Block:

@Override public void finalize() { 

     synchronized (this) 
     { 
      try 
      { 
       super.finalize(); 
      } 
      finally 
      { 
       finalized = true; 
      } 
     } 
    } 
Verwandte Themen