Compte tenu de la multitine suivante:
public class Multiton { private static final Multiton[] instances = new Multiton[...]; private Multiton(...) { //... } public static Multiton getInstance(int which) { if(instances[which] == null) { instances[which] = new Multiton(...); } return instances[which]; } }
5 Réponses :
Vous pouvez utiliser un tableau de serrures, au moins être capable d'obtenir différentes instances simultanément:
private static final Multiton[] instances = new Multiton[...]; private static final Object[] locks = new Object[instances.length]; static { for (int i = 0; i < locks.length; i++) { locks[i] = new Object(); } } private Multiton(...) { //... } public static Multiton getInstance(int which) { synchronized(locks[which]) { if(instances[which] == null) { instances[which] = new Multiton(...); } return instances[which]; } }
Attention à ce que c'est beaucoup i> plus difficile d'écrire la version non bloquante pour cela, en raison de la sémantique de la matrice volatil.
Cela vous permettra d'obtenir des instances différentes simultanément, mais y a-t-il une solution de contournement à la synchronisation inutile autour des exemples individuels? On dirait que nous sommes revenus au dilemme de verrouillage à double vérification à ce stade.
La solution de contournement la plus simple est d'initialiser avec impatience toutes les instances. C'est la solution la plus simple et est la meilleure dans de nombreux cas. Si la paresseuse est une exigence absolue, assurez-vous d'abord que la synchronisation simple constitue un problème de performance avant d'essayer de l'optimiser. La synchronisation est rapide, ou du moins beaucoup plus rapide que l'IO, l'accès à la base de données, les appels interprocessés, les algorithmes O (n ^ 2), etc. Ne préparez pas. C'est la racine de tout mal.
Cela vous fournira un mécanisme de stockage de threadsafe pour vos multitons. Le seul inconvénient est qu'il est possible de créer un multiron qui ne sera pas utilisé dans le putifabsent () strong> em> appel. La possibilité est petite mais elle existe. Bien sûr sur la chanson distante, cela se produit, cela ne provoque toujours aucun mal. sur le côté plus, il n'y a pas de préallocation ni d'initialisation requise et aucune restriction de taille prédéfinie. P> private static ConcurrentHashMap<Integer, Multiton> instances = new ConcurrentHashMap<Integer, Multiton>();
public static Multiton getInstance(int which)
{
Multiton result = instances.get(which);
if (result == null)
{
Multiton m = new Multiton(...);
result = instances.putIfAbsent(which, m);
if (result == null)
result = m;
}
return result;
}
putifabsent code> renvoie
null code> s'il n'y avait pas de mappage de la clé (voir le doc ). Ainsi,
résultat code> sera toujours null la première fois
getInstance code> est appelé.
Vous recherchez un Atomicreferencearray .
public class Multiton { private static final AtomicReferenceArray<Multiton> instances = new AtomicReferenceArray<Multiton>(1000); private Multiton() { } public static Multiton getInstance(int which) { // One there already? Multiton it = instances.get(which); if (it == null) { // Lazy make. Multiton newIt = new Multiton(); // Successful put? if ( instances.compareAndSet(which, null, newIt) ) { // Yes! it = newIt; } else { // One appeared as if by magic (another thread got there first). it = instances.get(which); } } return it; } }
Le problème avec cette solution est qu'il peut finir par appeler le constructeur de plusieurs fois multi-temps pour la même clé. Si le bloc d'enseil est exécuté, alors Newit est jeté car un autre fil a également fait l'objet.
@BryanRink - Vous êtes absolument correct. Il y a un meilleur ici est-ce un véritable multiton et est-ce le fil de sécurité et une java 8 ici
mise à jour: avec Java 8, il peut être encore plus simple: mmm c'est bien! p> réponse originale p>
Comme ça! Pourquoi le pendant (vrai) code>?
Dans la mise en œuvre initiale, le client peut annuler la tâche, auquel cas il est logique (si deux threads appellent GetInstance sur la même clé et on annule la tâche que vous ne voulez pas pénaliser l'autre). Dans mon exemple, il est redondant car cela ne peut pas arriver. Je vais nettoyer ça.
Est-ce que fonctionne de manière prédictive si
obtenez code> est appelé avant
exécuter code>?
@OldcurMudgeon Oui, il attend jusqu'à ce que la course soit appelée.
Est-il possible avec cette approche de mémoizeur pour ajouter des paramètres au constructeur multiton? Par exemple. Nomofcreator, GenderOfcreator. Je ne peux penser à aucune façon depuis que appelable.call () code> a une liste de paramètres vide.
@Mike en supposant que les paramètres sont transmis à getInstance code>, vous pouvez créer l'appelable à la vole pour renvoyer un
Nouveau multiton (paramètres) code> au lieu du CRÉATEUR CODE> STANDARD code> un. Je penserais également que si la même clé est appelée avec différents paramètres, cela pourrait entraîner une certaine confusion ...
Je pensais juste à utiliser le motif de mémoire dans une usine abstraite dans un autre contexte parce que j'ai tellement aimé ça. Quoi qu'il en soit, merci pour le conseil!
Quel est le comportement de futurettask si deux threads appellent ()? Je suppose que la tâche n'est exécutée qu'une seule fois, mais les Javadocs ne sont pas clairs à 100% sur ce point. EDIT: Je réalise maintenant que cela n'arrivera pas ici, car il est appelé () est seulement appelé par le fil qui a mis avec succès () le futuretask.
Avec l'avènement de Java 8 et quelques améliorations de ConcurrentMap CODE> et Lambdas Il est maintenant possible d'implémenter un
Multiton code> (et probablement même un
singleton code >) À une mode beaucoup à teneur:
// Get the instance associated with the specified key.
public static Multiton getInstance(final Integer key) throws InterruptedException, ExecutionException {
// Put it in - only create if still necessary.
return multitons.computeIfAbsent(key, k -> new Multiton());
}
Pourquoi cela vous fait-il mal à l'aise?
@assylia - Parce que je dois encore avoir la tête autour du concept de transmission de paramètres aux méthodes que potentiellement exécutées. Que New Multiton () CODE> regarde sur moi et l'habitude dit Un objet est en cours de création i>. Je sais que c'est irrationnel - je dois juste y faire face.
Vous savez que j'ai entendu dire qu'il y a cette technique appelée n'utilisant jamais d'un état mutable global (sauf lorsque les cadres vous obligent à).
Avez-vous des preuves que la synchronisation «coûteuse» (mais vraiment simple à obtenir) de la méthode
getinstance code> serait en fait significative dans votre application?
Non, c'est avant tout un exercice académique. Comme Singleton Synchronisation semble déjà être un sujet débattu, je me demandais si la solution de contournement de la classe interne pour Singletons s'étend de quelque manière que ce soit de multitons.