Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[Servlet] Les singletons fonctionnent-ils avec la méthode init

5 réponses
Avatar
Stéphane
Bonjour,

Je me tape la tête contre les murs car il y a quelque chose que je ne
comprends pas avec la méthode init des servlets. J'utilise Java 1.5 avec
un Tomcat 5.5.12.

Je voulais lancer un scheduler à partir de la méthode init de la
première servlet instanciée. Mais je me rends compte que le singleton
qui permet de créer l'instance du scheduler ne fonctionne pas comme je
le voudrais. Voici le code du singleton:

public class Singleton {
private static Object instance = null;

/**
* Singleton
*/
private Singleton() {}

public static synchronized Object newInstance() {
if (instance!=null) return(instance);
instance = new Object();
return(instance);
}
}

Et voici comment je l'appelle dans la méthode "init":
synchronized (System.out) {
System.out.println("@@@@ Thread n°"+Thread.currentThread().getId()+":
"+Singleton.newInstance());
}

Dans la méthode "init", j'obtiens ceci sur la console:
@@@@ Thread n°1: java.lang.Object@19113f8
@@@@ Thread n°1: java.lang.Object@17779e3

Deux instances de la servlet sont créées semble-t-il mais le singleton
retourne 2 instances différentes.

Si je fais la même chose dans la méthode "service" de la servlet et que
je l'appelle x fois, j'ai bien des lignes du genre:
@@@@ Thread n°32: java.lang.Object@425743
@@@@ Thread n°32: java.lang.Object@425743
@@@@ Thread n°31: java.lang.Object@425743
@@@@ Thread n°32: java.lang.Object@425743
@@@@ Thread n°31: java.lang.Object@425743
@@@@ Thread n°32: java.lang.Object@425743

Donc, d'ou vient le problème ?


Merci pour votre aide.

Stéphane

--
Plug'n dev
N'installez plus d'IDE pour développer en Java/J2EE/C/C++.
http://plugndev.toutprogrammer.com/

5 réponses

Avatar
jeanlutrin
Salut,

Pour commencer, je me suis fait avoir par ta methode newInstance()
qui ne cree pas une nouvelle instance : un nom tel getInstance()
par exemple serait plus approprie ;)

Ensuite, ce n'est pas la bonne facon de creer un singleton. De
nombreuses solutions plus complexes les unes que les autres ont
ete proposees pour resoudre le probleme de la creation d'un
singleton, y compris la solution tres creative (et tres boguee)
nommee "double checked locking".

Ce probleme est tellement courant que des grands noms du monde
Java ont publie un article a ce sujet, signe par de nombreuses
authorites en la matiere (notamment Joshua Bloch et Doug Lea) :

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Il existe pourtant quelques facons simples (et correctes) de creer un
singleton. Par exemple :

public class Singleton {
private static final Object INST = new Singleton();

private Singleton() {}

public static Object getInstance() {
return INST;
}
}

Ca, ca t'assure que ta classe soit bien un singleton... Ton singleton
sera instantie au chargement de la classe par le ClassLoader et ne
sera pas collecte par le ramasse-miette tant que le ClassLoader
existera. Il existe d'autres solutions si tu desires, par exemple,
utiliser la "lazy initiation" pour ton singleton...

Si apres avoir change ton programme de test pour qu'il utilise un
vrai singleton tu remarques toujours le meme probleme, c'est que
plusieurs ClassLoader chargent ton singleton, par exemple
parceque tu aurais deux Web apps differentes utilisant cette classe.

Si apres avoir modifie ton programme tu as toujours le probleme,
il faut regarder du cote des ClassLoader. Le lien suivant pourra
peut-etre t'aider :

http://tomcat.apache.org/tomcat-5.0-doc/class-loader-howto.html


A+,

Jean
Avatar
Stéphane
[...]
Si apres avoir change ton programme de test pour qu'il utilise un
vrai singleton tu remarques toujours le meme probleme, c'est que
plusieurs ClassLoader chargent ton singleton, par exemple
parceque tu aurais deux Web apps differentes utilisant cette classe.



Je viens de faire le test avec le singleton que vous proposez mais le
problème est le même.

Si apres avoir modifie ton programme tu as toujours le probleme,
il faut regarder du cote des ClassLoader. Le lien suivant pourra
peut-etre t'aider :

http://tomcat.apache.org/tomcat-5.0-doc/class-loader-howto.html



Je vais aller voir en espérant trouver la raison de cette bizarrerie.

Merci.

Stef

--
Plug'n dev
N'installez plus d'IDE pour développer en Java/J2EE/C/C++.
http://plugndev.toutprogrammer.com/

Avatar
obere
Les servlets ne sont instanciees qu'une seule fois: il n'y a pas une
instance de servlet par requete, mais une seule instance de la servlet
par laquelle passe toutes les requetes.
Accessoirement cela veut dire que tu ne devrais pas avoir besopin d'un
singleton pour ton object, si l'idee est de le partager entre les
requetes sur tes servlets.

Pour en revenir a ton probleme, c'est assez etrange de voir deux logs
sur le init de la servlet, puisque comme je l'ai dit la servlet ne
devrait etre cree qu'une seule fois.

Est il possible qu'elle soit creee deux fois dans deux ClassLoader
different (ce qui expliquerait aussi pourquoi ton singleton est cree
deux fois) ?? Je ne connais pas assez Tomcat pour repondre, mais il
pourrait etre utile de rajouter a ton log le class loader qui cree le
singleton:

synchronized (System.out) {
Singleton singleton = Singleton.newInstance();
System.out.println("@@@@ Thread
n°"+Thread.currentThread().getId()+":
"+singleton + " classloader=" + singleton.getClass().getClassLoader());

}
Avatar
fabrice-pas-despame.bacchella
On Tue, 21 Feb 2006 01:00:14 +0100, Stéphane
wrote:

Bonjour,

Je me tape la tête contre les murs car il y a quelque chose que je ne
comprends pas avec la méthode init des servlets. J'utilise Java 1.5 avec
un Tomcat 5.5.12.

Je voulais lancer un scheduler à partir de la méthode init de la
première servlet instanciée. Mais je me rends compte que le singleton


C'est pas directement la réponse, mais ça me semble plus simple :
passe par un ServletContextListener.

Avatar
Stéphane
Bonjour,


synchronized (System.out) {
Singleton singleton = Singleton.newInstance();
System.out.println("@@@@ Thread
n°"+Thread.currentThread().getId()+":
"+singleton + " classloader=" + singleton.getClass().getClassLoader());

}



J'ai fait au plus simple (car j'ai passé trop de temps à chercher): j'ai
recréé la webapp, la servlet et tout semble parfait maintenant.

Merci pour votre aide.

Stéphane

--
Plug'n dev
N'installez plus d'IDE pour développer en Java/J2EE/C/C++.
http://plugndev.toutprogrammer.com/