On 7 June 2011 21:49,  <mben...@apache.org> wrote:
> Author: mbenson
> Date: Tue Jun  7 20:49:04 2011
> New Revision: 1133155
>
> URL: http://svn.apache.org/viewvc?rev=1133155&view=rev
> Log:
> [JXPATH-141] FunctionLibrary Multithreading issue

I don't think this is fully thread-safe.

Although the byNamespace Map is created under a lock, another thread
may bypass the synch. block.
For non-final fields to be published correctly, both the writer and
reader threads need to use the same lock.

I suggest removing the double-check on the lock, i.e. just make the
functionCache() method synchronised.
If the map has already been created, the code path is very short.

> Modified:
>    
> commons/proper/jxpath/trunk/src/java/org/apache/commons/jxpath/FunctionLibrary.java
>
> Modified: 
> commons/proper/jxpath/trunk/src/java/org/apache/commons/jxpath/FunctionLibrary.java
> URL: 
> http://svn.apache.org/viewvc/commons/proper/jxpath/trunk/src/java/org/apache/commons/jxpath/FunctionLibrary.java?rev=1133155&r1=1133154&r2=1133155&view=diff
> ==============================================================================
> --- 
> commons/proper/jxpath/trunk/src/java/org/apache/commons/jxpath/FunctionLibrary.java
>  (original)
> +++ 
> commons/proper/jxpath/trunk/src/java/org/apache/commons/jxpath/FunctionLibrary.java
>  Tue Jun  7 20:49:04 2011
> @@ -20,6 +20,7 @@ import java.util.ArrayList;
>  import java.util.HashMap;
>  import java.util.Iterator;
>  import java.util.List;
> +import java.util.Map;
>  import java.util.Set;
>
>  /**
> @@ -32,8 +33,8 @@ import java.util.Set;
>  * @version $Revision$ $Date$
>  */
>  public class FunctionLibrary implements Functions {
> -    private List allFunctions = new ArrayList();
> -    private HashMap byNamespace = null;
> +    private final List allFunctions = new ArrayList();
> +    private Map byNamespace;
>
>     /**
>      * Add functions to the library
> @@ -59,10 +60,7 @@ public class FunctionLibrary implements
>      * @return Set<String>
>      */
>     public Set getUsedNamespaces() {
> -        if (byNamespace == null) {
> -            prepareCache();
> -        }
> -        return byNamespace.keySet();
> +        return functionCache().keySet();
>     }
>
>     /**
> @@ -75,10 +73,7 @@ public class FunctionLibrary implements
>      */
>     public Function getFunction(String namespace, String name,
>             Object[] parameters) {
> -        if (byNamespace == null) {
> -            prepareCache();
> -        }
> -        Object candidates = byNamespace.get(namespace);
> +        Object candidates = functionCache().get(namespace);
>         if (candidates instanceof Functions) {
>             return ((Functions) candidates).getFunction(
>                 namespace,
> @@ -105,28 +100,34 @@ public class FunctionLibrary implements
>     /**
>      * Prepare the cache.
>      */
> -    private void prepareCache() {
> -        byNamespace = new HashMap();
> -        int count = allFunctions.size();
> -        for (int i = 0; i < count; i++) {
> -            Functions funcs = (Functions) allFunctions.get(i);
> -            Set namespaces = funcs.getUsedNamespaces();
> -            for (Iterator it = namespaces.iterator(); it.hasNext();) {
> -                String ns = (String) it.next();
> -                Object candidates = byNamespace.get(ns);
> -                if (candidates == null) {
> -                    byNamespace.put(ns, funcs);
> -                }
> -                else if (candidates instanceof Functions) {
> -                    List lst = new ArrayList();
> -                    lst.add(candidates);
> -                    lst.add(funcs);
> -                    byNamespace.put(ns, lst);
> -                }
> -                else {
> -                    ((List) candidates).add(funcs);
> +    private Map functionCache() {
> +        if (byNamespace == null) {
> +            synchronized (this) {
> +                //read again
> +                if (byNamespace == null) {
> +                    byNamespace = new HashMap();
> +                    int count = allFunctions.size();
> +                    for (int i = 0; i < count; i++) {
> +                        Functions funcs = (Functions) allFunctions.get(i);
> +                        Set namespaces = funcs.getUsedNamespaces();
> +                        for (Iterator it = namespaces.iterator(); 
> it.hasNext();) {
> +                            String ns = (String) it.next();
> +                            Object candidates = byNamespace.get(ns);
> +                            if (candidates == null) {
> +                                byNamespace.put(ns, funcs);
> +                            } else if (candidates instanceof Functions) {
> +                                List lst = new ArrayList();
> +                                lst.add(candidates);
> +                                lst.add(funcs);
> +                                byNamespace.put(ns, lst);
> +                            } else {
> +                                ((List) candidates).add(funcs);
> +                            }
> +                        }
> +                    }
>                 }
>             }
>         }
> +        return byNamespace;
>     }
>  }
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to