J'ai une fonction qui utilise Pattern#compile
et un Matcher
pour rechercher une liste de chaînes pour un motif.
Cette fonction est utilisée dans plusieurs threads. Chaque thread aura un modèle unique transmis au Pattern#compile
lorsque le fil est créé. Le nombre de threads et de modèles est dynamique, ce qui signifie que je peux ajouter plus de Pattern
et de threads pendant la configuration.
Dois-je mettre un synchronize
sur cette fonction si elle utilise l'expression régulière? Est-ce que regex dans Java thread safe?
Oui , à partir de la documentation Java API pour la classe Pattern
Les instances de cette classe (Pattern) sont immuables et peuvent être utilisées en toute sécurité par plusieurs threads simultanés. Les instances de la classe Matcher ne sont pas sûres pour une telle utilisation.
Si vous recherchez du code centré sur les performances, essayez de réinitialiser l'instance Matcher à l'aide de la méthode reset (), au lieu de créer de nouvelles instances. Cela réinitialiserait l'état de l'instance Matcher, la rendant utilisable pour la prochaine opération d'expression régulière. En fait, c'est l'état maintenu dans l'instance Matcher qui est responsable de son danger pour l'accès simultané.
Thread-safety avec des expressions régulières en Java
SOMMAIRE:
L'API Java expression régulière a été conçue pour permettre à un modèle compilé unique d'être partagé entre plusieurs opérations de correspondance.
Vous pouvez appeler en toute sécurité Pattern.matcher () sur le même modèle à partir de différents threads et utiliser en toute sécurité les matchers simultanément. Pattern.matcher () est sûr de construire des matchers sans synchronisation. Bien que la méthode ne soit pas synchronisée, interne à la classe Pattern, une variable volatile appelée compilée est toujours définie après la construction d'un modèle et lue au début de l'appel à matcher (). Cela force tout thread se référant au Pattern à "voir" correctement le contenu de cet objet.
D'un autre côté, vous ne devez pas partager un Matcher entre différents threads. Ou du moins, si vous l'avez déjà fait, vous devez utiliser une synchronisation explicite.
Alors que vous devez vous rappeler que la sécurité des threads doit également prendre en compte le code environnant, vous semblez avoir de la chance. Le fait que Matchers sont créés en utilisant la méthode d'usine matcher du Pattern et manquent de constructeurs publics est un signe positif. De même, vous utilisez la méthode statique compiler pour créer le Pattern englobant.
Donc, en bref, si vous faites quelque chose comme l'exemple:
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
vous devriez vous débrouiller plutôt bien.
Suivi de l'exemple de code pour plus de clarté: notez que cet exemple implique fortement que le Matcher ainsi créé est thread-local avec le Pattern et le test. C'est-à-dire que vous ne devez pas exposer le Matcher ainsi créé à d'autres threads.
Franchement, c'est le risque de toute question de sécurité des threads. La réalité est que tout code peut être rendu thread-dangereux si vous essayez assez fort. Heureusement, il y a merveilleuxlivres qui nous apprennent tout un tas de façons dont nous pourrions ruiner notre code. Si nous restons à l'écart de ces erreurs, nous réduisons considérablement notre propre probabilité de problèmes de threading.
Un aperçu du code de Matcher.Java
montre un tas de variables membres, y compris le texte qui est mis en correspondance, des tableaux pour les groupes, quelques index pour maintenir l'emplacement et quelques boolean
s pour les autres états. Tout cela pointe vers un Matcher
avec état qui ne se comporterait pas bien s'il était accessible par plusieurs Threads
. Il en va de même pour JavaDoc :
Les instances de cette classe ne sont pas sûres pour une utilisation par plusieurs threads simultanés.
Ce n'est un problème que si, comme le souligne @Bob Cross, vous vous efforcez d'autoriser l'utilisation de votre Matcher
dans des Thread
s séparés. Si vous devez le faire et que vous pensez que la synchronisation sera un problème pour votre code, une option que vous avez consiste à utiliser un objet de stockage ThreadLocal
pour maintenir un Matcher
par thread de travail.
Pour résumer, vous pouvez réutiliser (conserver dans des variables statiques) le (s) modèle (s) compilé (s) et leur dire de vous donner de nouveaux Matchers lorsque cela est nécessaire pour valider ces patrons d'expression régulière par rapport à une chaîne
import Java.util.regex.Matcher;
import Java.util.regex.Pattern;
/**
* Validation helpers
*/
public final class Validators {
private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$";
private static Pattern email_pattern;
static {
email_pattern = Pattern.compile(EMAIL_PATTERN);
}
/**
* Check if e-mail is valid
*/
public static boolean isValidEmail(String email) {
Matcher matcher = email_pattern.matcher(email);
return matcher.matches();
}
}
voir http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-Java/ (vers la fin) concernant le modèle RegEx utilisé ci-dessus pour valider les e-mails (au cas où cela ne correspondrait pas aux besoins de validation des e-mails tels qu'ils sont publiés ici)