首页 > 解决方案 > InetAddress 不是线程安全的?

问题描述

我们使用jdk1.8。例外情况如下:

Caused by: java.lang.NullPointerException
    at java.net.InetAddress$Cache.put(InetAddress.java:806)
    at java.net.InetAddress.cacheAddresses(InetAddress.java:885)
    at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1362)
    at java.net.InetAddress.getAllByName0(InetAddress.java:1276)
    at java.net.InetAddress.getAllByName(InetAddress.java:1192)
    at java.net.InetAddress.getAllByName(InetAddress.java:1126)
    at java.net.InetAddress.getByName(InetAddress.java:1076)
    at java.net.InetSocketAddress.<init>(InetSocketAddress.java:220)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:451)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:546)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:214)
    at sun.net.www.http.HttpClient.New(HttpClient.java:326)
    at sun.net.www.http.HttpClient.New(HttpClient.java:345)
    ...........
    ...........

从第 828,829 行开始,Cache 不会将null放入地图中。

但是,InetAddress在缓存地址时使用了同步。

所以不知道为什么会抛出NullPointerException。

注意,缓存是由 InetAddress 而不是用户管理的。我想知道为什么它会抛出npe。这是不可能的。

相关代码如下:

网络地址:

    // InetAddress
    private static void cacheAddresses(String hostname,
                                       InetAddress[] addresses,
                                       boolean success) {
        hostname = hostname.toLowerCase();
        synchronized (addressCache) {
            cacheInitIfNeeded();
            if (success) {
885                addressCache.put(hostname, addresses);
886            } else {
887                negativeCache.put(hostname, addresses);
            }
        }
    }


缓存:

      ublic Cache put(String host, InetAddress[] addresses) {
            int policy = getPolicy();
            if (policy == InetAddressCachePolicy.NEVER) {
                return this;
            }

            // purge any expired entries

            if (policy != InetAddressCachePolicy.FOREVER) {

                // As we iterate in insertion order we can
                // terminate when a non-expired entry is found.
                LinkedList<String> expired = new LinkedList<>();
                long now = System.currentTimeMillis();
                for (String key : cache.keySet()) {
                    CacheEntry entry = cache.get(key);

806                    if (entry.expiration >= 0 && entry.expiration < now) {
807                        expired.add(key);
808                    } else {
809                        break;
                    }
                }

                for (String key : expired) {
                    cache.remove(key);
                }
            }

            // create new entry and add it to the cache
            // -- as a HashMap replaces existing entries we
            //    don't need to explicitly check if there is
            //    already an entry for this host.
            long expiration;
            if (policy == InetAddressCachePolicy.FOREVER) {
                expiration = -1;
            } else {
                expiration = System.currentTimeMillis() + (policy * 1000);
            }
828            CacheEntry entry = new CacheEntry(addresses, expiration);
829            cache.put(host, entry);
830            return this;
        }

标签: javasynchronizationthread-safetyinetaddress

解决方案


推荐阅读