I think this raises a more fundamental question, as to why the URL hashCode() and equals() methods delegates to URLStreamHandler in the first place? rather than performing the processing within the URL class itself, and synchronizing appropriately within.

If you call equals() and hasCode() concurrently on the same URL instance, there exists the possibility (slight) that the hostAddress could be set differently, when it is being set for the first time, without the synchronization of the getHostAddress() in the URLStreamHandler.

Although it may rarely happen the mechanics of InetAddress.getByName() potentially, lend itself to a different return address on multiple calls, as it returns the first address from a array of addresses retrieved - assumption is that the ordering will always be the same.

regards
Mark

On 25/11/2014 12:58, Wang Weijun wrote:
On Nov 25, 2014, at 20:25, Pavel Rappo <pavel.ra...@oracle.com> wrote:

Hi Max,

I don't see any particular reason for this. Maybe it's just a "precaution". It 
seems to me it's the only field
of the URL class set directly (without setter) from an outside.

Does it hurt performance a lot? In what cases?
There is a 7x difference in my experiment on SecureClassLoader.defineClass().

Or, it can be shown using this benchmark:

package org.openjdk.bench;

import org.openjdk.jmh.annotations.*;

import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@State(Scope.Benchmark)
public class Weird {
     final int num = 100;
     final Object[] urls = new Object[num];

     public static class CS {
         private final Object url;
         public CS(Object url) { this.url = url; }
         public int hashCode() { return url.hashCode(); }
         public boolean equals(Object o) { return o instanceof CS && 
url.equals(((CS)o).url); }
     }

     private final Map<Object, Object> pdcacheC = new ConcurrentHashMap<>();

     @Setup
     public void init() throws Exception {
         for (int i=0; i< num; i++) {
             urls[i] = new URL("file:/tmp/"+i);
         }
     }

     @State(Scope.Thread)
     public static class ThreadState {
         final Random rand = new Random();
     }


     @Benchmark
     public void setC(ThreadState state) throws IOException {
         Object cs = new CS(urls[next(state)]);
         pdcacheC.computeIfAbsent(cs, x -> "");
     }

     private int next(ThreadState state) {
         return state.rand.nextInt(num);
     }
}

--Max


-Pavel

On 25 Nov 2014, at 12:02, Wang Weijun <weijun.w...@oracle.com> wrote:

I am benchmarking security manager and notice this

protected synchronized InetAddress getHostAddress(URL u) {
   if (u.hostAddress != null)
       return u.hostAddress;

   String host = u.getHost();
   if (host == null || host.equals("")) {
       return null;
   } else {
       try {
           u.hostAddress = InetAddress.getByName(host);
       } catch (UnknownHostException ex) {
           return null;
       } catch (SecurityException se) {
           return null;
       }
   }
   return u.hostAddress;
}

Is there any reason why the method is synchronized? Why not simply "synchronized 
(u)"?

Thanks
Max


Reply via email to