美文网首页
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