2012-05-01 14 views
6

Spesso devo url codificare o decodificare una grande collezione o array di stringhe. Oltre a scorrere su di essi e utilizzare lo statico URLDecoder.decode (stringa, "UTF-8"), ci sono delle librerie là fuori che renderanno questo tipo di operazione più performante?Esiste una libreria Java comune che gestirà la codifica/decodifica degli URL per una raccolta di stringhe?

Un collega insiste sul fatto che l'utilizzo del metodo statico per decodificare le stringhe sul posto non è thread-safe. Perché dovrebbe essere?

+0

A meno che il metodo statico si basi su variabili statiche nella classe URLDecoder, ogni chiamata di metodo va sullo stack separatamente ed è thread-safe. Non vedo alcun motivo per cui URLDecoder.decode (...) abbia bisogno di accedere alle risorse condivise. – Thomas

risposta

7

Il JDK URLDecoder non è stata attuata in modo efficiente. In particolare, internamente si basa su StringBuffer (che introduce inutilmente la sincronizzazione nel caso di URLDecoder). Il comune di Apache fornisce URLCodec, ma è stato segnalato che presenta problemi simili per quanto riguarda le prestazioni, ma non ho verificato che sia ancora il caso nella versione più recente.

Mark A. Ziesemer ha scritto un post un po 'indietro sui problemi e le prestazioni con URLDecoder. Ha registrato alcune segnalazioni di bug e ha finito per scrivere una sostituzione completa. Perché questo è così, io cito alcuni brani chiave qui, ma si dovrebbe davvero leggere l'intero articolo fonte qui: http://blogger.ziesemer.com/2009/05/improving-url-coder-performance-java.html

citazioni selezionati:

Java fornisce un'implementazione predefinita di questa funzionalità in java .net.URLEncoder e java.net.URLDecoder. Sfortunatamente, non è il il più performante, sia per il modo in cui è stata scritta l'API che per i dettagli dello all'interno dell'implementazione. Un numero di bug correlati alle prestazioni è stato archiviato su sun.com in relazione a URLEncoder.

C'è un'alternativa: org.apache.commons.codec.net.URLCodec da Apache Commons Codec. (Commons Codec fornisce anche un'utile implementazione per la codifica Base64.) Sfortunatamente, l'URLCodec Commons di Commons presenta alcuni degli stessi problemi di URLEncoder/URLDecoder di Java.

...

Raccomandazioni per entrambe le JDK e Comuni:

Quando si costruisce una qualsiasi delle classi "buffer", ad esempio ByteArrayOutputStream, CharArrayWriter, StringBuilder o StringBuffer, stima e accesso una capacità stimata. Lo strumento URLEncoder di JDK lo fa attualmente per il suo StringBuffer, ma dovrebbe fare anche questo per l'istanza CharArrayWriter. Common URLCodec dovrebbe fare questo per la sua istanza ByteArrayOutputStream. Se le dimensioni dei buffer predefinite delle classi sono troppo piccole, potrebbe essere necessario ridimensionarle copiando in buffer nuovi, più grandi, che non è esattamente un'operazione "economica". Se le dimensioni del buffer predefinito delle classi sono troppo grandi, la memoria potrebbe essere inutilmente sprecata.

Entrambe le implementazioni dipendono dai set di caratteri, ma le accettano solo come come nome di stringa. Charset fornisce una cache semplice e piccola per le ricerche dei nomi - memorizzando solo gli ultimi 2 set di caratteri utilizzati. Questo non dovrebbe essere fatto su , ed entrambi dovrebbero accettare istanze Charset per altri motivi di interoperabilità pure.

Entrambe le implementazioni gestiscono solo ingressi e uscite di dimensioni fisse. L'URLEncoder di JDK funziona solo con le istanze String. Commons 'URLCodec si basa anche su stringhe, ma funziona anche con array byte []. Questo è un vincolo a livello di progettazione che essenzialmente impedisce l'elaborazione efficiente di input di lunghezza maggiore o variabile. Invece, dovrebbero essere supportate le interfacce "stream-supporting" come CharSequence, Appendable e java.nio's Buffer implementazioni di ByteBuffer e CharBuffer.

...

Nota che com.ziesemer.utils.urlCodec è finita 3x veloce come il JDK URLEncoder, e più di 1,5x veloce come il JDK URLDecoder. (Del JDK URLDecoder è stato più veloce rispetto alla URLEncoder, quindi non c'era tanto margini di miglioramento.)

Penso che il vostro collega è sbagliato suggerire urldecode non è thread-safe. Altre risposte qui spiegano in dettaglio.

EDIT [2012-07-03] - Per commentare in seguito inviato da OP

Non

sicuro se si fosse alla ricerca di ulteriori idee o no? Hai ragione nel dire che se intendi operare sulla lista come una raccolta atomica, allora dovresti sincronizzare tutti gli accessi alla lista, inclusi i riferimenti al di fuori del tuo metodo. Tuttavia, se si sta bene con il contenuto dell'elenco restituito potenzialmente diverso dall'elenco originale, quindi un approccio a forza bruta per operare su un "batch" di stringhe da una raccolta che potrebbe essere modificata da altri thread potrebbe essere simile a questo:

Se ciò non aiuta, quindi non sono ancora sicuro di cosa si sta cercando e sarebbe meglio servire per creare una nuova, più concisa, domanda. Se è quello che stavi chiedendo, fai attenzione perché questo esempio fuori contesto non è una buona idea per molte ragioni.

+0

Grazie. Probabilmente avrei dovuto dividerlo in due domande separate: una su una libreria java per codificare/decodificare intere collezioni o array di stringhe e una sul problema di sicurezza dei thread. WRLC Apache's URLCodec, sembra funzionare solo su una stringa o un oggetto alla volta. I confronti delle prestazioni mostrati sono utili. – jrws

+0

WRT il problema di sicurezza del thread, avrei dovuto fornire più contesto (o lasciato il problema per un'altra domanda, per favore perdona il noob). Per quanto riguarda il problema, il problema di sicurezza del thread si è verificato perché la raccolta per eseguire la sostituzione dei valori sul posto è un argomento del metodo: public foo (elenco stringhe). La raccolta stessa viene chiamata in base al valore, ma gli oggetti a cui fa riferimento sono ancora riferimenti a oggetti, quindi sembra che la sincronizzazione sia la cosa più sicura da fare, dal momento che non ho il controllo sull'utilizzo dei chiamanti di questa raccolta. Qualcosa del genere ... – jrws

+0

... public foo (Lista stringhe) {Lista decodedStrings = Collezioni. synchronizedList (stringhe); synchronized (decodedStrings) {for (String decodedString: decodedStrings) {decodedString = URLDecoder.decode (decodedString, "UTF-8")}}}} – jrws

0

Apache ha URLCodec che può essere utilizzato per la codifica della decodifica.

Se il metodo statico funziona solo sulle variabili locali o sulle variabili inizializzate finali, è completamente thread-safe.

Poiché i parametri vivono in pila e sono completamente thread-safe, le costanti finali sono immutabili e pertanto non possono essere modificate.

seguito il codice è completamente thread-safe:

public static String encodeMyValue(String value){ 
    // do encoding here 
} 

Si deve prestare attenzione se le variabili finali sono mutabili nel senso che non si può riassegnare, ma si può cambiare la sua rappresentazione interna (proprietà).

0

La sicurezza del thread non è mai realmente necessaria con le funzioni statiche (o si tratta di un errore di progettazione). Soprattutto, se non si accede nemmeno alle variabili statiche della classe.

Io suggerirei di usare la funzione che hai usato prima, e l'iterazione attraverso la raccolta

0

Fondamentalmente non esiste alcuna protezione del thread magico applicata a metodi statici o metodi di istanza o costruttori. Possono essere tutti richiamati contemporaneamente su più thread, a meno che non venga applicata la sincronizzazione. Se non recuperano o cambiano dati condivisi, in genere sono sicuri: se accedono ai dati condivisi, è necessario prestare maggiore attenzione.

quindi Nel tuo caso è possibile scrivere il metodo sincronizzato su questa urldecoding o codifica mediante il quale è possibile applicare esternamente la sicurezza dei thread.