|
7 | 7 | import java.net.InetAddress; |
8 | 8 |
|
9 | 9 | public final class HostNameResolver { |
10 | | - private static final MethodHandle HOLDER_GET; |
11 | | - private static final MethodHandle HOSTNAME_GET; |
| 10 | + private static volatile MethodHandle HOLDER_GET; |
| 11 | + private static volatile MethodHandle HOSTNAME_GET; |
12 | 12 |
|
13 | 13 | private static final DDCache<String, String> HOSTNAME_CACHE = DDCaches.newFixedSizeCache(64); |
14 | 14 |
|
15 | | - static { |
16 | | - MethodHandle holderTmp = null, hostnameTmp = null; |
17 | | - try { |
18 | | - final ClassLoader cl = HostNameResolver.class.getClassLoader(); |
19 | | - final MethodHandles methodHandles = new MethodHandles(cl); |
| 15 | + private HostNameResolver() {} |
| 16 | + |
| 17 | + public static void tryInitialize() { |
| 18 | + if (HOLDER_GET != null) { |
| 19 | + return; // fast path: already initialized |
| 20 | + } |
| 21 | + synchronized (HostNameResolver.class) { |
| 22 | + if (HOLDER_GET != null) { |
| 23 | + return; // double-check: another thread just succeeded |
| 24 | + } |
| 25 | + MethodHandle holderTmp = null, hostnameTmp = null; |
| 26 | + try { |
| 27 | + final ClassLoader cl = HostNameResolver.class.getClassLoader(); |
| 28 | + final MethodHandles methodHandles = new MethodHandles(cl); |
20 | 29 |
|
21 | | - final Class<?> holderClass = |
22 | | - Class.forName("java.net.InetAddress$InetAddressHolder", false, cl); |
23 | | - holderTmp = methodHandles.method(InetAddress.class, "holder"); |
24 | | - if (holderTmp != null) { |
25 | | - hostnameTmp = methodHandles.method(holderClass, "getHostName"); |
| 30 | + final Class<?> holderClass = |
| 31 | + Class.forName("java.net.InetAddress$InetAddressHolder", false, cl); |
| 32 | + holderTmp = methodHandles.method(InetAddress.class, "holder"); |
| 33 | + if (holderTmp != null) { |
| 34 | + hostnameTmp = methodHandles.method(holderClass, "getHostName"); |
| 35 | + } |
| 36 | + } catch (Throwable ignored) { |
| 37 | + holderTmp = null; |
26 | 38 | } |
27 | | - } catch (Throwable ignored) { |
28 | | - holderTmp = null; |
29 | | - } finally { |
| 39 | + // volatile writes ensure visibility to other threads |
30 | 40 | if (holderTmp != null && hostnameTmp != null) { |
31 | | - HOLDER_GET = holderTmp; |
32 | 41 | HOSTNAME_GET = hostnameTmp; |
33 | | - } else { |
34 | | - HOLDER_GET = null; |
35 | | - HOSTNAME_GET = null; |
| 42 | + HOLDER_GET = holderTmp; // written last: signals successful initialization |
36 | 43 | } |
37 | 44 | } |
38 | 45 | } |
39 | 46 |
|
40 | | - private HostNameResolver() {} |
41 | | - |
42 | 47 | static String getAlreadyResolvedHostName(InetAddress address) { |
| 48 | + if (HOLDER_GET == null) { |
| 49 | + tryInitialize(); |
| 50 | + } |
43 | 51 | if (HOLDER_GET == null) { |
44 | 52 | return null; |
45 | 53 | } |
|
0 commit comments