Java Regex è sicuro?

Ho una funzione che usa la Pattern#compile e un Matcher per cercare un elenco di stringhe per un pattern.

Questa funzione è utilizzata in più thread. Ogni thread avrà uno schema univoco passato alla Pattern#compile del Pattern#compile quando viene creato il thread. Il numero di thread e pattern è dinamico, il che significa che posso aggiungere più Pattern e thread durante la configurazione.

Devo mettere una synchronize su questa funzione se usa regex? L’espressione regolare nel thread Java è sicura?

, dalla documentazione dell’API Java per la class Pattern

Le istanze di questa class (Pattern) sono immutabili e sono sicure per l’uso da più thread simultanei. Le istanze della class Matcher non sono sicure per tale uso.

Se stai guardando il codice delle prestazioni, prova a reimpostare l’istanza di Matcher usando il metodo reset (), invece di creare nuove istanze. Ciò ripristinerebbe lo stato dell’istanza Matcher, rendendolo utilizzabile per la successiva operazione regex. In effetti, è lo stato mantenuto nell’istanza Matcher a essere responsabile della sua insicurezza per l’accesso simultaneo.

Sicurezza dei thread con espressioni regolari in Java

SOMMARIO:

L’API di espressioni regolari Java è stata progettata per consentire la condivisione di un singolo modello compilato tra più operazioni di corrispondenza.

È ansible chiamare in modo sicuro Pattern.matcher () sullo stesso pattern da thread diversi e utilizzare in modo sicuro i match in concomitanza. Pattern.matcher () è sicuro per build matcher senza sincronizzazione. Sebbene il metodo non sia sincronizzato, interno alla class Pattern, una variabile volatile chiamata compilata viene sempre impostata dopo aver costruito un modello e letto all’inizio della chiamata a matcher (). Questo forza qualsiasi thread che si riferisce al Pattern per “vedere” correttamente il contenuto di quell’object.

D’altra parte, non si dovrebbe condividere un Matcher tra thread diversi. O almeno, se mai l’hai fatto, dovresti usare la sincronizzazione esplicita.

Mentre è necessario ricordare che la sicurezza del thread deve tener conto anche del codice circostante, sembra che tu abbia fortuna. Il fatto che i Matcher vengano creati utilizzando il metodo Factory di Matcher e la mancanza di costruttori pubblici è un segnale positivo. Allo stesso modo, si usa il metodo statico di compilazione per creare il Pattern che comprende.

Quindi, in breve, se fai qualcosa come l’esempio:

 Pattern p = Pattern.compile("a*b"); Matcher m = p.matcher("aaaaab"); boolean b = m.matches(); 

dovresti fare abbastanza bene.

Follow-up dell’esempio di codice per chiarezza: si noti che questo esempio implica fortemente che il Matcher così creato sia thread-local con il Pattern e il test. Ad esempio, non dovresti esporre il Matcher creato in tal modo a nessun altro thread.

Francamente, questo è il rischio di qualsiasi domanda sulla sicurezza del filo. La realtà è che qualsiasi codice può essere reso poco sicuro se ci provi abbastanza. Fortunatamente ci sono libri meravigliosi che ci insegnano un sacco di modi per rovinare il nostro codice. Se rimaniamo lontani da questi errori, riduciamo notevolmente la nostra probabilità di problemi di threading.

Una rapida occhiata al codice per Matcher.java mostra un gruppo di variabili membro tra cui il testo che viene abbinato, gli array per i gruppi, alcuni indici per mantenere la posizione e alcuni s boolean per l’altro stato. Tutto questo punta a un Matcher stateful che non si comporta bene se vi si accede da più Threads . Così fa il JavaDoc :

Le istanze di questa class non sono sicure per l’utilizzo da più thread simultanei.

Questo è solo un problema se, come sottolineato da @Bob Cross, ti lasci andare per consentire l’utilizzo del tuo Matcher in Thread separati. Se è necessario eseguire questa operazione e si ritiene che la sincronizzazione sia un problema per il codice, è necessario utilizzare un object di archiviazione ThreadLocal per mantenere un Matcher per thread di lavoro.

Per riassumere, puoi riutilizzare (mantenere in variabili statiche) i Pattern compilati e dire loro di darti nuovi Matchers quando necessario per convalidare i pattern di regex contro una stringa

 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(); } } 

vedere http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-java/ (vicino alla fine) per quanto riguarda il pattern RegEx usato in precedenza per validare le e-mail ( nel caso in cui non soddisfi i requisiti per la convalida della posta elettronica come viene pubblicato qui)