美文网首页
03 String#intern

03 String#intern

作者: 格林哈 | 来源:发表于2020-11-19 17:23 被阅读0次

    1 String

    • 使用方法

      • 直接使用双引号声明出来的String对象会直接存储在常量池中。
      • 如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
    • String#intern

      • 会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
      • 实现
        • JAVA 使用 JNI 调用 c++ 实现的 StringTable 的 intern 方法, StringTable的 intern 方法跟 Java 中的 HashMap 的实现是差不多的, 只是不能自动扩容。默认大小是1009
      • JVM 参数指定
        • -XX:StringTableSize=99991
        • image.png

    2 案例

    public class StringTest2 {
        public static void main(String[] args) {
            String s = new String("111");
            s.intern();
            String s2 = "111";
            System.out.println(s == s2);
    
            String s3 = new String("1") + new String("1");
            s3.intern();
            String s4 = "11";
            System.out.println(s3 == s4);
    
            char[] strs = {'a','b'};
            String s5 = new String(strs,0,2);
            s5.intern();
            String s6 = "ab";
            System.out.println(s5 == s6);
    
        }
    }
    
    // 输出
    false
    true
    true
    
    • jdk8解释

      • s s2

        • String s = new String("111"); 首先 把 111 放入常量池

          • 堆中新建一个 String 对象, 实例数据 value[] 指向 常量池 111 的value[]
          • s 引用 存储 新建的 String 对象引用。
        • s.intern();

          • 常量池已经存在 111 s2 存储 常量池 111 引用
        • s == s2 false

      • s3,s4

        • new String("1") + new String("1");
        • 会优化成 s3 = new StringBuilder("1").append("1").toString();
          • StringBuilder.toString 方法
            • new String(value, 0, count);
          • 所以s5 s6 跟 s3,s4 是一样的。
      • s5,s6

        • String s5 = new String(strs,0,2);
          • 新建 String 对象,this.value = Arrays.copyOfRange(value, offset, offset+count);
          • s5 存储 堆中 ab String 对象引用
        • s5.intern();
          • 常量池不存在 ab, 常量池 不需要存储一份对象,直接存储 堆中引用。
          • s6 存储 堆中 ab String 对象引用
        • s5 == s6 true
    • 可能的问题

      • JDK 自带的 String Pool 固定大小,不支持自动扩容
      • c++ StringTable 实现 类似java HashMap,
        • 散列表 数量太多就会 导致 hash冲突严重,链地址 链变长,性能变差。

    3 Eureka StringCache

    • 使用场景
      • appName 服务名
      • appGroupName 组名
      • vipAddress 虚拟主机名
      • 元数据 key,value 等等。
    • image.png
    /**
     * An alternative to {@link String#intern()} with no capacity constraints.
     *  String#intern() 的替代选择,没有容量限制。
     *
     * @author Tomasz Bak
     */
    public class StringCache {
    
        public static final int LENGTH_LIMIT = 38;
    
        private static final StringCache INSTANCE = new StringCache();
    
        private final ReadWriteLock lock = new ReentrantReadWriteLock();
        //key 不存在 强引用,下次gc 直接回收
        private final Map<String, WeakReference<String>> cache = new WeakHashMap<String, WeakReference<String>>();
        private final int lengthLimit;
    
        public StringCache() {
            this(LENGTH_LIMIT);
        }
    
        public StringCache(int lengthLimit) {
            this.lengthLimit = lengthLimit;
        }
    
        public String cachedValueOf(final String str) {
            if (str != null && (lengthLimit < 0 || str.length() <= lengthLimit)) {
                // Return value from cache if available 从缓存返回值(如果有)
                try {
                    lock.readLock().lock();
                    WeakReference<String> ref = cache.get(str);
                    if (ref != null) {
                        return ref.get();
                    }
                } finally {
                    lock.readLock().unlock();
                }
    
                // Update cache with new content 用新内容更新缓存
                try {
                    lock.writeLock().lock();
                    WeakReference<String> ref = cache.get(str);
                    if (ref != null) {
                        return ref.get();
                    }
                    cache.put(str, new WeakReference<>(str));
                } finally {
                    lock.writeLock().unlock();
                }
                return str;
            }
            return str;
        }
    
        public int size() {
            try {
                lock.readLock().lock();
                return cache.size();
            } finally {
                lock.readLock().unlock();
            }
        }
    
        public static String intern(String original) {
            return INSTANCE.cachedValueOf(original);
        }
    }
    

    相关文章

      网友评论

          本文标题:03 String#intern

          本文链接:https://www.haomeiwen.com/subject/fleliktx.html