11
votes

Multiples threads appelant la méthode de l'assistance statique

J'ai une application Web fonctionnant sur tomcat.

Il y a plusieurs calculs à effectuer sur plusieurs endroits de l'application Web. Puis-je faire ces calculs des fonctions d'aide statique? Si le serveur dispose de suffisamment de cœurs de processeur, de multiples appels sur cette fonction statique (résultant de plusieurs demandes à différents servlets) sont-elles parallèles? Ou une demande doit-elle attendre que l'autre demande ait terminé l'appel? xxx

si les appels fonctionnent parallèlement: J'ai une autre classe d'assistance avec des fonctions statiques, mais cette classe contient un élément statique privé utilisé dans les fonctions statiques. Comment puis-je vous assurer que les fonctions sont du thread-coffre-fort? xxx

changeValue () et readvalue () Lire / Modifier la même variable de membre de helper.obj . Dois-je rendre les fonctions statiques entières synchronisées ou simplement le bloc où helper.obj est utilisé? Si je devais utiliser un bloc, quel objet dois-je utiliser pour le verrouiller?


1 commentaires

Merci à tous, vous avez certainement répondu à ma question et m'a également donné de la nourriture pour la pensée. Malheureusement, je ne peux pas accepter plusieurs réponses: - /


7 Réponses :


5
votes

Vous devez capturer les calculs dans une classe et créer une instance de la classe pour chaque fil. Ce que vous avez maintenant n'est pas threadsafe, comme vous le savez, et de le faire threadsafe, vous devrez vous synchroniser sur la ressource statique / les méthodes qui accèdent à cette ressource statique, ce qui entraînera du blocage.

Notez qu'il existe des motifs pour vous aider avec cela. Vous pouvez utiliser le modèle de stratégie (sous sa forme canonique, la stratégie doit être choisie au moment de l'exécution, qui pourrait ou non s'appliquer ici) ou une variante. Il suffit de créer une classe pour chaque calcul avec une méthode d'exécution (et une interface contenant la méthode) et transmettez un objet de contexte à exécuter. Le contexte détient tout l'état du calcul. Une instance de stratégie par fil, avec son contexte, et vous ne devriez pas avoir de problèmes.


8 commentaires

Le premier cas d'utilisation n'a pas besoin d'être en sécurité, car il n'ya que des paramètres primitifs et aucun membre de la classe impliqué. ou ai-je manqué quelque chose là-bas?


@Mariop, c'est vrai, mais en général, cela peut être accompli avec des instances sans trop de difficulté, ma réponse est donc de s'éloigner des méthodes statiques toutes ensemble. Ce n'est pas bon IMHO si la moitié des calculs sont dans des méthodes statiques et que l'autre moitié sont dans des instances ...


@Mario Si aucun état n'est stocké dans les champs de classe ( statique ou non statique), alors vous allez bien.


@hvgotcodes, si je fais une classe instanciable normale ou utilisez le modèle de stratégie pour ces calculs, comment cela affecte-t-il l'application en termes d'utilisation de la mémoire? La surcharge est-elle négligeable?


@Mariop, il y a toujours un coût pour une instance de la classe - que le coût est relativement petit. Si chaque calcul entraîne beaucoup de données avec elle, cela sera vrai si vous utilisez des méthodes statiques ou non. Combien d'instances de calculs envisagez-vous d'avoir?


@hvgotcodes, je ne peux pas vraiment dire ça. Je ne sais pas combien de clients utiliseront l'application plus tard. Le seul "numéro" que j'ai eu quand j'ai demandé était "autant que possible".


@Mariop sont ces calculs à long terme? Je suppose donc si vous utilisez le filetage


@HVGOTCODES, il y aura de longs calculs de course, mais il n'y aura aucun moyen pour l'utilisateur de les appeler avec un servlet. Pour ceux-ci, je pensais à une sorte de ... Quelle est la description anglaise pour cela? Emploi BATCH?



6
votes

Puis-je faire des calculs statiques des fonctions statiques? Si le serveur dispose de suffisamment de cœurs de processeur, de multiples appels sur cette fonction statique (résultant de plusieurs demandes à différents servlets) fonctionnent parallèlement? P>

Oui, et oui. P>

Dois-je rendre les fonctions statiques entières synchronisées p> blockQuote>

qui fonctionnera. P>

ou juste le bloc où helper.obj code> est utilisé p> blockQuote>

qui fonctionnera également. P>

Si je devrais utiliser un bloc, quel objet dois-je utiliser pour le verrouiller? p> blockQuote>

Utilisez un objet statique code>: p>

public class Helper {

    private static SomeObject obj;
    private static final Object mutex = new Object();

    public static void changeMember() {
        synchronized (mutex) {
            obj.changeValue();
        }
    }

    public static String readMember() {
        synchronized (mutex) {
            obj.readValue();
        }
    }
}


13 commentaires

Dans le contexte d'une application Web avec une charge inconnue, la synchronisation sur une verrouillage statique peut provoquer des problèmes de performance. En fonction de la charge et du temps passé dans le code synchronisé. J'ai vu des "solutions" qui ont causé un serveur d'applications totalement inutilisable: avec une énorme file d'attente de demandes en attente d'être servi sur ce goulot d'étranglement.


Certains objets doivent être partagés, la gestion de la session par exemple. Quelle serait une solution élégante pour cela?


@Mario Pourriez-vous clarifier ce que vous voulez dire? "Gestion de la session" n'est pas un objet.


@Tomasz Stanczak J'accepte d'être conscient et j'ai un coup d'œil étroit sur ce code, mais ne pas la synchroniser si nécessaire n'est pas une alternative. Ou que recommanderiez-vous alors?


@Matt Balle, il doit être objet de créer, de supprimer, de valider et de gérer généralement des identifiants de session. Il en va de même pour les manipulaires d'entreprise, etc. Ces objets doivent être partagés (de sorte qu'il n'y a pas de sessions en double et, etc.).


Vous devriez laisser le conteneur gérer la gestion de la session! N'utilisez-vous pas httpservletQuest #Getsession () ?


@Matt balle, la direction de la session n'est pas encore mise en œuvre (mais je dois admettre que je n'ai pas prévu d'utiliser httpsession). Néanmoins, il existe des objets qui doivent être partagés sur des demandes, par ex. Verrouillage d'une composante métier, de sorte que deux utilisateurs ne puissent pas éditer le même objet. Les informations de verrouillage doivent être stockées quelque part. Cela doit être statique, non?


@Mario: "Les informations de verrouillage doivent être stockées quelque part. Cela doit être statique, non?" - définitivement pas!


@Matt balle, tu viens de détruire ma vue sur le monde. Quelles sont les alternatives, sauf écrivant les informations dans une base de données?


@Mario Si vous souhaitez empêcher l'accès simultané à un seul composant Business, vous pouvez simplement synchroniser dessus, non?


@Matt balle, je ne veux pas empêcher l'accès simultané. Il existe un composant d'entreprise "Vendeur" pour charger et sauvegarder un fournisseur de la base de données / à la base de données, mais il peut y avoir des centaines de fournisseurs différents. Je veux juste empêcher que deux utilisateurs puissent éditer le même fournisseur en même temps. User1 doit enregistrer ses modifications de Vendorx avant que User2 puisse modifier Vendorx, mais User2, User3 et userX devrait pouvoir modifier Vendor2 ou voir Vendeur


@Mario Cette question est suffisamment charnue et suffisamment différente de votre question initiale, que vous voudrez peut-être simplement poser une nouvelle question pour cela.


vous avez raison. Je penserai à ce que j'ai lu et revenez si la question est pertinente après la refonte.



0
votes

Si vous êtes inquiet de la synchronisation et de la sécurité du thread, n'utilisez pas d'aides statiques. Créez une classe normale avec vos méthodes d'assistance et créez une instance sur demande de servlet. Gardez-le simple: -)


1 commentaires

Je ne suis pas d'accord. Avoir de bonnes méthodes utilitaires statiques est très courante et une bonne chose. Cela réduit le code de copie et collez et conserve les choses «propres» et simples, car moins complexes.



4
votes

Si vous n'avez pas à partager, vous pouvez le faire filer local, alors il ne doit pas nécessairement être le fil en sécurité.

public class Helper {

private static final ThreadLocal<SomeObject> obj = new ThreadLocal<SomeObject>() {
    public SomeObject initialValue() {
        return enw SomeObject();
    }
}

public static void changeMember() {
    Helper.obj.get().changeValue();
}

public static String readMember() {
    Helper.obj.get().readValue();
}

}


1 commentaires

Malheureusement, il doit être partagé, mais je vais jeter un coup d'œil à la classe Threadlocal. Peut-être que cela se révèle utile dans un autre contexte.



1
votes

Dans le premier cas, vous n'avez pas à vous soucier des problèmes de threading, car les variables sont locales à chaque fil. Vous identifiez correctement le problème dans le second cas, car plusieurs threads seront en train de lire / écrire le même objet. La synchronisation sur les méthodes fonctionnera, de même que les blocs synchronisés.


0 commentaires

1
votes

pour la première partie: Oui, ces appels sont indépendants et fonctionnent en parallèle lorsqu'ils sont appelés par différents threads.

Pour la dernière partie: Utilisez des blocs de synchronisation sur l'objet simultané, un objet factice ou un objet de classe. Soyez conscient des blocs de synchronisation en cascade. Ils peuvent conduire en verrouillons morts lorsqu'ils sont acquis dans un ordre différent.


0 commentaires

2
votes

Je vais résumer ici ce qui a été dit dans les commentaires à la réponse de la balle Matt, car il est assez long à la fin et que le message est perdu: et le message était

Dans un environnement partagé, comme un serveur Web / applications, vous devez essayer de trouver une solution sans synchronisation. L'utilisation d'aides statiques synchronisées sur un objet statique peut fonctionner suffisamment bien pour que l'application autonome avec un seul utilisateur devant l'écran, dans un scénario multi-utilisateurs / multipiapplications, cela se termine très probablement dans une très mauvaise performance - cela signifie effectivement sérialisé l'accès à Votre candidature, tous les utilisateurs devraient attendre sur le même verrou. Vous ne remarquerez peut-être pas le problème pendant une longue période: si le calcul est suffisamment rapide et que la charge est distribuée de manière uniforme.

Mais tout d'un coup, tous vos utilisateurs peuvent essayer de passer par le calcul à 9h du matin et que votre application s'arrêtera pour fonctionner! Je veux dire pas vraiment arrêter, mais ils bloqueraient tous sur la serrure et faire une énorme file d'attente.

Maintenant, quelle que soit la nécessité d'un État partagé, puisque vous avez initialement nommé des calculs à l'origine de la synchronisation: les résultats doivent être partagés? Ou sont ces calculs spécifiques à un utilisateur / session? Dans ce dernier cas, un threadlocal selon Peter Lawrey serait suffisant. Sinon, je dirais pour la performance globale Il serait préférable de faire dupliquer les calculs de tout le monde qui les ait besoin pour ne pas synchroniser (dépend du coût).

La direction de la session doit également être mieux à gauche au conteneur: il a été optimisé pour les gérer efficacement, si nécessaire, y compris la clustering, etc. Je doute que l'on puisse faire une meilleure solution sans investir beaucoup de travail et gagner beaucoup de bugs sur le chemin . Mais comme la balle mat déclarée devrait être mieux demandée séparément.


0 commentaires