1

Ca faisait longtemps que j'avais pas un peu balancé sur Java, alors je propose d'en remettre une couche, sur un thème précis :

Comment implémenteriez-vous un singleton en Java ?
Dans un programme threadé.

Oui je sais, la question pue. C'est fait exprès, pour voir si Java est si intuitif qu'il prétend.

2

La réponse que t'attends, c'est celle où il faut faire gaffe à ne pas créer l'instance et affecter l'attribut statique de la classe du même coup, à cause d'une sombre histoire de variable initialisée alors que l'instance n'est pas encore prête ? (de mémoire, je ne fais pas de Java; ms ça doit se trouver sur google)

Si c'est ça, oui c'est moche, anti-intuitif et source d'erreurs. Mais je ne comprends pas l'intérêt du topic : si l'objectif est juste de collectionner le plus grand nombre de trolls possible (cf "Pourquoi Linux c'est bien/mal"), faites-vous une catégorie pour ça (d'ailleurs il en existe déjà une il me semble) et évitez de pourrir tout yN... zzz
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

3

Cette implémentation ne te convient pas : http://fr.wikipedia.org/wiki/Singleton_(patron_de_conception)#Java ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

4

class singleton {
  private static Object instance=null;
  private singleton() { }
  public static synchronized Object getInstance() {
    if(instance==null) instance=new Object();
    return instance;
  }
}


non?

edit: ah, y'avait une feinte?

5

Je fais comme dans l'alternative du lien proposé par Sasume.

6

squalyl (./4) :
class singleton {
  private static Object instance=null;
  private singleton() { }
  public static synchronized Object getInstance() {
    if(instance==null) instance=new Object();
    return instance;
  }
}


non?

ah, y'avait une feinte, merci Zephyr.


en java, les attributs sont initialisés par défaut (obj à null, bool à false et nombres à 0)
Et l'alternative du lien proposé par Sasume est bien plus élégante à mon avis.

7

(cross, oui c'est vrai, OTAN pour moi)
encore plus couillon:

class singleton {
  private static Object instance;
  static {
    instance=new Object();
  }
  private singleton() { }
  public static synchronized Object getInstance() {
    return instance;
  }
}
(ce qui revient au même code, puisque l'init des champs est faite dans <clinit>)

8

Mais ça (l'alternative du lien et aussi la solution du ./7) initialise le singleton tout de suite, pas seulement à la première requête. Donc ce n'est pas la même chose.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

9

avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

10

y'a pas besoin de synchroniser la méthode getinstance tongue

11

./9> C'est un hack pourri pour contourner le synchronized ça, les exemples avec synchronized fonctionnent.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

12

Kevin Kofler (./8) :
Mais ça (l'alternative du lien et aussi la solution du ./7) initialise le singleton tout de suite, pas seulement à la première requête. Donc ce n'est pas la même chose.

sauf erreur, c'est à la première utilisation de la classe. Donc ce n'est pas ce que j'appelerais *tout de suite*

13

./11 : c'était peut-être justement là où voulait en venir Spectras, l'existence de ce "synchronized" (enfin je ne suis pas à sa place, il faudra attendre qu'il reposte ^^)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

14

dans tous les cas c'est de la pure branlette intellectuelle.

si la méthode est synchronisée y'a qu'un thread qui peut l'appeler donc même si l'allocation et l'appel au constructeur ne sont pas atomiques, la synchronisation de la méthode supprime le problème.

L'erreur c'est de mettre le bloc synchronisé dans le if uniquement.

15

squalyl (./14) :
L'erreur c'est de mettre le bloc synchronisé dans le if uniquement.

en même temps, ça ne me viendrait pas à l'idée confus (et comme je répète, de toutes façons y'a pas besoin de synchroniser avec l'alternative)

16

je suis d'accord mais c'est ça qu'ils proposent triso

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {
      instance = new Singleton();
    }
  }
  return instance;
}


et la branlette elle est là:
The code in Listing 2 [le mien quoi] works fine for multithreaded access to the getInstance() method. However, when you analyze it you realize that synchronization is required only for the first invocation of the method.

17

Ba ça me semble évident qu'il y a un bug dans le code que tu cites triso
De toutes façons quelqu'un qui connait le java construit son objet dans du code statique et puis voilà.
C'est vraiment contre productif ce genre d'articles #trizzz#

18

Hop désolé j'avais du taff.
Donc l'implémentation de ./3 et ./4 marche oui, mais elle est très très lente, parce qu'elle nécessite une synchronisation systématique, ce qui est extrèmement coûteux, surtout sur un environnement matériellement multithreadé. C'est fortement contre productif, alors qu'en réalité une fois le singleton initialisé la synchronisation n'est plus utile.

D'où la question : comment éviter de plomber fortement les performances, en évitant cette synchronisation ?

Zephyr> oui, c'est là que je veux en venir

19

ben, on y a déjà répondu n fois :
public class Singleton
{
   public static Singleton getInstance()
   {
      return s ;
   }
   private static Singleton s= new Singleton() ; // instancié UNE fois, à la première utilisation de la classe
   private Singleton()
   {
   }
}


public class Plop 
{ 
    public static void main( String[] args ) 
   { 
      Singleton s1= Singleton.getInstance() ; 
      Singleton s2= Singleton.getInstance() ; 
      assert s1==s2 : "rhha, s1 != s2 #sniff#" ; 
   } 
}


Je ne vois pas ou tu lis un "synchronized" dans ce source ! (et je ne vois pas comment on pourrait encore accelerer getInstance, vu qu'on ne peut pas inliner)

20

Alors :
1) Si je me souviens bien, ton code n'est pas thread-safe sans mettre ta variable static en final. Ce qui est quand même assez limitatif.
2) Même avec final ça répond pas à la question, parce que la jvm va faire une synchronisation quand même à chaque utilisation de la variable.

21

et puis instinctivement on aurait quand même tendance à instancier la classe dans la méthode getInstance, puisque c'est habituellement la forme qu'on retrouve partout, et justement elle pose problème en Java pour des raisons assez complexes (bien trop complexes pour un langage qui se veut haut niveau en tout cas)

(rah j'ai marché dedans... !sortez_moi_d'ici)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

22

Prends un peu d'ice, Zephyr.
508209611_d4fe40c207_o.jpg
avatar
Fahrenheit 451, Brave New World, 1984 : make your choice

23

ah si j'avais le temps... hehe
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

24

squalyl (./16) :
je suis d'accord mais c'est ça qu'ils proposent triso

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {
      instance = new Singleton();
    }
  }
  return instance;
}


et la branlette elle est là:
The code in Listing 2 [le mien quoi] works fine for multithreaded access to the getInstance() method. However, when you analyze it you realize that synchronization is required only for the first invocation of the method.


Si je ne me trompe pas, le code que tu as cité est mauvais... (oui c'est pas ta faute mais bon grin)
Pour plus de détails http://en.wikipedia.org/wiki/Double-checked_locking
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

25

./1 > Si c’est juste pour balancer sur Java, j’OSE © espérer que tu as un autre langage à nous proposer qui, lui, n’a pas le problème que tu cites.
Peut-être est-ce le cas, peut-être ne l’est-ce pas, je n’en sais rien, je ne connais pas les langages concurrents de Java.

./all > Notez que, dans tous les exemples, il y a une ÉNORME #cb# faille : la méthode clone() détruit le caractère unique de l’instance.
Un Singleton doit donc obligatoirement surcharger clone() }
 :    @Override
    public final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException() ;
   
avatar
Je ne suis pas développeur Java : je suis artiste Java.
Ce que l’on conçoit bien s’énonce clairement, / Et le code pour l’écrire arrive aisément.
Hâtez-vous lentement ; toujours, avec méthode, / Vingt fois dans l’IDE travaillez votre code.
La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer.
You don't use science to show that you're right, you use science to become right.

26

27

pour être clonable, une classe ne doit pas explicitement implementer cloneable ?
je vais vérifier.

28

public class A
{
	public static void main( String[] args )
		throws java.lang.CloneNotSupportedException
	{
		new A().clone() ;
	}
}


donne

Exception in thread "main" java.lang.CloneNotSupportedException: A
        at java.lang.Object.clone(Native Method)
        at A.main(A.java:8)


C'est bien ce que je pensais tongue

(Et si tu veux bloquer l'héritage, tu déclares A finale et puis hop embarrassed)

29

30

Pen^2 (./28) :
(Et si tu veux bloquer l'héritage, tu déclares A finale et puis hop embarrassed)
C’est en effet un problème d’héritage : si une classe dérive de Singleton, elle pourrait, elle, implémenter Cloneable.
Et même si ça paraît débile de marquer explicitement comme Cloneable une classe dérivant d’un Singleton, il faut se dire que que Singleton ne portera peut-être pas un nom si spécifique et n’aura peut-être pas de documentation.

Certes, on peut marquer le Singleton final, mais peut-être aura-t-on besoin un jour d’en dériver, c’est donc d’après moi une mauvaise idée.

Comme une implémentation de clone() est censée appeler super.clone(), ce clone() du Singleton devrait suffire, mais si le programmeur ne le fait pas (zOMGWTFBBQ eek), une protection supplémentaire est de le marquer final (le clone(), pas le Singleton).
Hop, je corrige hehe.
avatar
Je ne suis pas développeur Java : je suis artiste Java.
Ce que l’on conçoit bien s’énonce clairement, / Et le code pour l’écrire arrive aisément.
Hâtez-vous lentement ; toujours, avec méthode, / Vingt fois dans l’IDE travaillez votre code.
La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer.
You don't use science to show that you're right, you use science to become right.