Hi,
Some time ago I dived into the sinchronization pitfalls of URL /
URLStreamHandler and came up with a possible solution. Here's the thread
(mostly just my comments) and a patch:
http://mail.openjdk.java.net/pipermail/net-dev/2014-July/008592.html
Regards, Peter
On 11/25/2014 03:03 PM, Mark Sheppard wrote:
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