2012-05-01 6 views
6

Ich muss oft eine große Sammlung oder ein Array von Strings kodieren oder dekodieren. Abgesehen von der Iteration und dem statischen URLDecoder.decode (String, "UTF-8") gibt es Bibliotheken, die diese Art von Operationen leistungsfähiger machen?Gibt es eine gemeinsame Java-Bibliothek, die URL-Codierung/Decodierung für eine Sammlung von Zeichenfolgen behandelt?

Ein Kollege besteht darauf, dass die statische Methode zum Dekodieren der Strings nicht threadsicher ist. Warum sollte das sein?

+0

Sofern sich die statische Methode nicht auf statische Variablen in der URLDecoder-Klasse verlässt, wird jeder Methodenaufruf separat auf den Stack gesetzt und ist Thread-sicher. Ich sehe keinen Grund, warum URLDecoder.decode (...) Zugriff auf freigegebene Ressourcen benötigen würde. – Thomas

Antwort

7

Das JDK URLDecoder nicht effizient umgesetzt wurde durch die Sammlung iterieren. Vor allem intern basiert es auf StringBuffer (was bei URLDecoder unnötigerweise die Synchronisation einführt). Apache Commons bietet URLCodec, aber es wurde auch berichtet, dass ähnliche Probleme in Bezug auf die Leistung haben, aber ich habe nicht überprüft, dass das immer noch der Fall in der neuesten Version ist.

Mark A. Ziesemer hat einen Beitrag über die Probleme und die Leistung mit URLDecoder eine Weile zurück geschrieben. Er protokollierte einige Fehlerberichte und schrieb schließlich einen kompletten Ersatz. Weil dies so ist, werde ich einige wichtige Auszüge hier zitieren, aber Sie sollten wirklich die gesamte Quelle Artikel hier lesen: http://blogger.ziesemer.com/2009/05/improving-url-coder-performance-java.html

Ausgewählte Zitate:

Java eine Standardimplementierung dieser Funktionalität in Java bietet .net.URLEncoder und java.net.URLDecoder. Leider ist es nicht die beste Leistung, aufgrund sowohl wie die API geschrieben wurde, als auch Details innerhalb der Implementierung. Eine Reihe von leistungsbezogenen Bugs wurden auf sun.com in Bezug auf URLEncoder eingereicht.

Es gibt eine Alternative: org.apache.commons.codec.net.URLCodec von Apache Commons Codec. (Commons Codec bietet auch eine nützliche Implementierung für Base64-Codierung.) Leider leidet Commons 'URLCodec einige der gleichen Probleme wie Javas URLEncoder/URLDecoder.

...

Empfehlungen sowohl für die JDK und Commons:

Wenn eine der "Puffer" Klassen konstruieren, zum Beispiel ByteArrayOutputStream, CharArrayWriter, StringBuilder oder StringBuffer, schätzen und übergeben eine geschätzte Kapazität. Der JDK URLEncoder tut dies derzeit für seinen StringBuffer, sollte aber dies auch für seine CharArrayWriter-Instanz tun. Common URLCodec sollte dies für seine ByteArrayOutputStream-Instanz tun. Wenn die Standardpuffergrößen der Klassen zu klein sind, müssen sie möglicherweise geändert werden, indem in neue, größere Puffer kopiert wird - was nicht gerade eine "billige" Operation ist. Wenn die Standard-Puffergrößen der Klassen zu groß sind, kann der Speicher unnötigerweise verschwendet werden.

Beide Implementierungen sind abhängig von Zeichensätzen, akzeptieren sie aber nur als ihren String-Namen. Charset bietet einen einfachen und kleinen Cache für Namens-Lookups - speichert nur die letzten 2 verwendeten Charsets. Dies sollte nicht verlassen werden, und beide sollten Charset-Instanzen für andere Interoperabilitätsgründe auch akzeptieren.

Beide Implementierungen verarbeiten nur Eingänge und Ausgänge fester Größe. Der JDK URLEncoder funktioniert nur mit String-Instanzen. Commons 'URLCodec basiert ebenfalls auf Strings, arbeitet aber auch mit byte [] Arrays. Dies ist eine Design-Level-Einschränkung, die eine effiziente Verarbeitung von größeren oder längenvariablen Eingängen von im Wesentlichen verhindert. Stattdessen sollten die "stream-supporting" Schnittstellen wie CharSequence, Appendable und java.nios Buffer Implementierungen von ByteBuffer und CharBuffer unterstützt werden. so schnell wie der JDK URLEncoder und über 1,5x so schnell wie das JDK URLDecoder

...

Beachten Sie, dass com.ziesemer.utils.urlCodec über 3x ist. (Die URLDecoder JDK war schneller als die URLEncoder, so dass es nicht so viel Raum für Verbesserungen.)

Ich denke, Ihr Kollege falsch ist URLDecode vorschlagen ist nicht Thread-sicher. Andere Antworten hier erklären im Detail.

EDIT [2012-07-03] - Per später Kommentiert von OP

Nicht sicher, ob Sie sich für weitere Ideen oder nicht gesucht haben? Sie haben Recht, wenn Sie beabsichtigen, die Liste als eine atomare Sammlung zu bearbeiten, müssen Sie alle Zugriffe auf die Liste synchronisieren, einschließlich der Referenzen außerhalb Ihrer Methode. Wenn Sie jedoch mit dem zurückgegebenen Listeninhalt einverstanden sind, der sich möglicherweise von der ursprünglichen Liste unterscheidet, könnte ein Brute-Force-Ansatz für die Ausführung eines "Stapels" von Strings aus einer Sammlung, die von anderen Threads modifiziert werden, ungefähr so ​​aussehen:

Wenn das nicht hilft, dann bin ich immer noch nicht sicher, was Sie suchen und Sie würden besser gedient, um eine neue, prägnantere Frage zu erstellen. Wenn Sie danach gefragt haben, dann seien Sie vorsichtig, weil dieses Beispiel außerhalb des Kontexts aus vielen Gründen keine gute Idee ist.

+0

Danke. Ich hätte das wahrscheinlich in zwei getrennte Fragen aufteilen sollen: eine über eine Java-Bibliothek zum Kodieren/Dekodieren von ganzen Sammlungen oder Arrays von Strings und eine über das Thread-Sicherheitsproblem. WRT Apache URLCodec, scheint dies immer noch nur für eine Zeichenfolge oder ein Objekt zu einer Zeit zu arbeiten. Die gezeigten Leistungsvergleiche sind hilfreich. – jrws

+0

WRT das Thread Sicherheitsproblem, ich hätte mehr Kontext zur Verfügung gestellt (oder das Problem für eine andere Frage, bitte vergeben Sie die Noob). So weit wie es geht, kam das Thread-Sicherheitsproblem auf, weil die Sammlung, um die In-Place-Substitution der Werte durchzuführen, ein Methodenargument ist: public foo (List strings). Die Sammlung selbst wird nach Wert aufgerufen, aber die Objekte, auf die sie verweist, sind immer noch Verweise auf Objekte, so dass es scheint, dass Synchronisation die sicherste Sache ist, da ich keine Kontrolle über die Verwendung dieser Sammlung durch den Aufrufer habe. So etwas ... – jrws

+0

... public foo (Liste Strings) {Liste decrectedStrings = Sammlungen. synchronizedList (Zeichenfolgen); synchronisiert (decodedStrings) {für (String decodedString: decodedStrings) {decodedString = URLDecoder.decode (decodedString, "UTF-8")}};} – jrws

0

Apache hat URLCodec, die für die Decodierung der Codierung verwendet werden kann.

Wenn Ihre statische Methode nur für die lokalen Variablen oder die endgültigen initialisierten Variablen funktioniert, ist sie vollständig Thread-sicher.

Da die Parameter auf dem Stack leben und sie vollständig Thread-sicher sind, sind die endgültigen Konstanten unveränderlich und können daher nicht geändert werden.

folgende Code ist vollständig Thread-sicher:

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

darauf geachtet werden sollte, wenn endgültige Variablen wandelbar sind bedeutet, dass Sie es nicht neu zuordnen kann, aber man kann seine interne Darstellung (Eigenschaften) ändern.

0

Gewindesicherheit ist eigentlich nie notwendig mit statischen Funktionen (oder es ist ein Konstruktionsfehler). Vor allem nicht, wenn sie nicht einmal auf statische Variablen in der Klasse zugreifen.

Ich würde vorschlagen, die Funktion, die Sie vor der Verwendung mit und

0

Grundsätzlich gibt es keine magische Thread-Sicherheit, die auf statische Methoden oder Instanzmethoden oder Konstruktoren angewendet wird. Sie können alle gleichzeitig auf mehreren Threads aufgerufen werden, sofern keine Synchronisierung angewendet wird. Wenn sie keine freigegebenen Daten abrufen oder ändern, sind sie im Allgemeinen sicher. Wenn sie auf freigegebene Daten zugreifen, müssen Sie vorsichtiger sein.

In diesem Fall können Sie eine synchronisierte Methode über diese URL-Kodierung oder Kodierung schreiben, mit der Sie die Thread-Sicherheit extern erzwingen können.

Verwandte Themen