2012-05-01 11 views
6

A menudo tengo que url codificar o decodificar una gran colección o conjunto de cadenas. Además de iterar a través de ellos y usar el URLDecoder.decode estático (cadena, "UTF-8"), ¿hay bibliotecas por ahí que harán que este tipo de operación sea más efectiva?¿Existe una biblioteca común de Java que manejará la codificación/decodificación URL para una colección de cadenas?

Un colega insiste en que usar el método estático para decodificar las cadenas en el lugar no es seguro para subprocesos. ¿Por qué sería eso?

+0

A menos que el método estático se base en variables estáticas en la clase URLDecoder, cada llamada al método va a la pila por separado y es segura para la ejecución de subprocesos. No veo ningún motivo por el que URLDecoder.decode (...) necesite ningún acceso a los recursos compartidos. – Thomas

Respuesta

7

El JDK URLDecoder no fue implementado de manera eficiente. En particular, internamente se basa en StringBuffer (que introduce innecesariamente la sincronización en el caso de URLDecoder). Apache commons proporciona URLCodec, pero también se ha informado que tiene problemas similares en cuanto al rendimiento, pero no he verificado que siga siendo así en la versión más reciente.

Mark A. Ziesemer escribió una publicación hace un tiempo sobre los problemas y el rendimiento con URLDecoder. Logró algunos informes de errores y terminó escribiendo un reemplazo completo. Debido a que esto es así, voy a citar algunos extractos clave aquí, pero que realmente debería leer el artículo original aquí: http://blogger.ziesemer.com/2009/05/improving-url-coder-performance-java.html

cotizaciones seleccionados:

Java proporciona una implementación por defecto de esta funcionalidad en java .net.URLEncoder y java.net.URLDecoder. Lamentablemente, no es el mejor rendimiento, tanto por la forma en que se escribió la API como por los detalles de dentro de la implementación. Se han presentado una serie de errores relacionados con el rendimiento en sun.com en relación con URLEncoder.

Existe una alternativa: org.apache.commons.codec.net.URLCodec de Apache Commons Codec. (Commons Codec también proporciona una implementación útil para la codificación Base64.) Desafortunadamente, Commons 'URLCodec sufre algunos de los mismos problemas que URLEncoder/URLDecoder de Java.

...

Recomendaciones para ambos el JDK y los Comunes:

Cuando la construcción de cualquiera de las clases "amortiguador", por ejemplo, ByteArrayOutputStream, CharArrayWriter, StringBuilder o StringBuffer, calcule y otorgue una capacidad estimada. El URLEncoder del JDK actualmente hace esto para su StringBuffer, pero debería hacer esto para su instancia CharArrayWriter también. El URLCodec de Common debería hacer esto para su instancia ByteArrayOutputStream. Si los tamaños predeterminados del buffer de las clases son demasiado pequeños, pueden tener que cambiar el tamaño copiando en nuevos buffers más grandes, lo cual no es exactamente una operación "barata". Si los tamaños de búfer predeterminados de las clases son demasiado grandes, la memoria puede ser innecesariamente desperdiciada.

Ambas implementaciones dependen de Charsets, pero solo las aceptan como su nombre de cadena. Charset proporciona un caché simple y pequeño para las búsquedas de nombre , que almacena solo los últimos 2 Charsets utilizados. Esto no se debe confiar en , y ambos deben aceptar instancias Charset para otras razones de interoperabilidad también.

Ambas implementaciones solo manejan entradas y salidas de tamaño fijo. El El URLEncoder de JDK solo funciona con instancias String. Commons 'URLCodec también se basa en cadenas, pero también funciona con matrices byte []. Esta es una restricción de nivel de diseño que esencialmente impide el procesamiento eficiente de entradas más grandes o de longitud variable. En su lugar, se deben admitir las interfaces " " de soporte de flujo tales como CharSequence, Appendable y las implementaciones Buffer de Buffer de ByteBuffer y CharBuffer de java.nio.

...

Tenga en cuenta que com.ziesemer.utils.urlCodec es más de 3 veces más rápido que el JDK URLEncoder, y más de 1,5 veces más rápido que el JDK URLDecoder. (Del JDK URLDecoder era más rápido que el URLEncoder, así que no había tanta margen de mejora.)

Creo que su colega es erróneo sugerir URLDecode no es seguro para subprocesos. Otras respuestas aquí explican en detalle.

EDITAR [2012-07-03] - Por más adelante comentario Publicado por OP

No

seguro de si estaban buscando más ideas o no? Tiene razón en que si tiene la intención de operar en la lista como una colección atómica, deberá sincronizar todo el acceso a la lista, incluidas las referencias fuera de su método. Sin embargo, si está de acuerdo con los contenidos de la lista devuelta que difieren potencialmente de la lista original, un enfoque de fuerza bruta para operar en un "lote" de cadenas de una colección que podría ser modificado por otros hilos podría ser similar a esto:

/** 
* @param origList will be copied by this method so that origList can continue 
*     to be read/write by other threads. 
* @return list containing decoded strings for each entry that was 
      in origList at time of copy. 
*/ 
public List<String> decodeListOfStringSafely(List<String> origList) 
     throws UnsupportedEncodingException { 
    List<String> snapshotList = new ArrayList<String>(origList); 
    List<String> newList = new ArrayList<String>(); 

    for (String urlStr : snapshotList) { 
     String decodedUrlStr = URLDecoder.decode(urlStr, "UTF8"); 
      newList.add(decodedUrlStr); 
    } 

    return newList; 
} 

Si eso no ayuda, entonces todavía no estoy seguro de lo que está buscando y sería mejor que lo haga para crear una nueva, más concisa, pregunta. Si eso es lo que preguntaba, tenga cuidado porque este ejemplo fuera de contexto no es una buena idea por muchas razones.

+0

Gracias. Probablemente debería haber dividido esto en dos preguntas separadas: una sobre una biblioteca java para codificar/decodificar colecciones enteras o matrices de cadenas y otra sobre el tema de seguridad de hilos. WRT Apache's URLCodec, esto parece funcionar solo en una cadena u objeto a la vez. Las comparaciones de rendimiento que demostró son útiles. – jrws

+0

WRT el problema de la seguridad del hilo, debería haber proporcionado más contexto (o dejé el tema para otra pregunta, perdona al novato). Hasta donde llega, surgió el problema de la seguridad del hilo porque la colección para realizar la sustitución in situ de los valores es un argumento de método: public foo (List strings). La colección en sí se llama por valor, pero los objetos a los que hace referencia siguen siendo referencias a objetos, por lo que parece confirmar que la sincronización es lo más seguro que se puede hacer, ya que no tengo control sobre el uso de esta colección por parte de los llamadores. Algo como esto ... – jrws

+0

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

0

Apache tiene URLCodec que se puede utilizar para codificar decodificación.

Si su método estático solo funciona en las variables locales o en las variables iniciales, entonces es completamente seguro para la ejecución de subprocesos.

Como los parámetros viven en la pila y son completamente seguros para hilos, las constantes finales son inmutables, por lo tanto no se pueden cambiar.

siguiente código está completamente hilo de seguridad:

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

Se debe tener cuidado si las variables finales son mutables que significa que no se puede reasignar pero puede cambiar su representación interna (propiedades).

0

Seguridad de subprocesos realmente nunca es realmente necesaria con funciones estáticas (o es una falla de diseño). Especialmente no, si ni siquiera acceden a Variables estáticas en la clase.

se recomienda usar la función que ha utilizado anteriormente, y la iteración a través de la colección

0

Básicamente no hay seguridad mágica de hilos aplicada a métodos estáticos o métodos de instancia o constructores. Todos se pueden invocar en varios subprocesos al mismo tiempo, a menos que se aplique la sincronización. Si no obtienen ni cambian ningún dato compartido, generalmente estarán seguros; si acceden a los datos compartidos, debe tener más cuidado.

por lo que en su caso puede escribir el método sincronizado en la parte superior de este urldecoding o codificación mediante el cual puede aplicar la seguridad del hilo externamente.

Cuestiones relacionadas