2016-06-13 6 views
4

Si jePeut-on appeler d'autres méthodes après finalize()?

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

Est-il garanti, même face à de multiples discussions, en supposant que le GC appellera finalize(), que le IllegalStateException ne sera jamais jeté?

Je sais que face à une méthode finalize() qui empêche l'objet d'être récupérable, l'objet ne sera pas récupéré et d'autres méthodes pourraient être appelées. Mais ce finalize() ne fait pas cela. Est-il toujours possible que foo() soit appelé après finalize()?

+1

Vouliez-vous dire demander, « après Finaliser a été appelé par le GC? Sinon, un idiot pourrait vous l'appeler explicitement. – bmargulies

+0

@bmargulies Merci, c'est ce que je voulais dire. – Owen

+0

vous devriez garder cette méthode protégée comme initialement défini dans Objet non public pour limiter le risque –

Répondre

7

Il est tout à fait possible qu'un objet différent qui avait une référence à l'instance de Foo est en cours de finalisation en même temps - et ressuscite l'objet Foo, ce qui permet de l'utiliser après la finalisation. C'est un peu impoli, mais peut certainement arriver.

Même sans la résurrection, une autre finaliseur pourrait appeler Foo.foo() de son finaliseur:

public class Bar { 
    private final Foo foo; 

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

Comme mentionné Jon Skeet, il est tout à fait possible des méthodes pour obtenir appelé alors un thread est actuellement dans votre processus de finalisation.

Pour vous prémunir contre cela, vous pouvez certainement rendre le code thread-safe.

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

Remarque: Pour faire preuve de prudence supplémentaire, je mettrais l'appel à super.finalize() dans un bloc try/finally:

@Override public void finalize() { 

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