> 文档中心 > 《从Java面试题看源码》-Java11中的toString与Java8的区别

《从Java面试题看源码》-Java11中的toString与Java8的区别

​​《从Java面试题看源码》-Java11中的toString与Java8的区别
在前面【《从Java面试题来看源码》-LinkedBlockingQueue 源码分析】的文章中,我们看到有一个toString方法是这样的:

public String toString() {    //    return Helpers.collectionToString(this);}

为什么要这样呢?

分析

使用Helpers类,来输出字符串,与Java8不同。 Helpers类用于并发包输出字符串,该类只在输出数组的时候获取锁,而不是在toString中获取锁

Java11中用到了Helpers.collectionToString(this)的方式输出字符串,并且与Java8是不同的。

先看看Java11中Helpers类的写法:

 /**     * Collection.toString() 的一种实现,适用于有锁的类。     * 代替了以前在整个toString()过程中加锁,或者在每次调用Iterator.next()的时候加锁     * 该方法只在调用toArray()期间加锁,以减少其他线程对访问集合时产生的影响     * 并且遵循在加锁期间,不调用任何外部代码     */static String collectionToString(Collection<?> c) {//这里toArray会加锁    final Object[] a = c.toArray();    final int size = a.length;    if (size == 0) return "[]";    int charLength = 0;    // Replace every array element with its string representation    for (int i = 0; i < size; i++) { Object e = a[i]; // Extreme compatibility with AbstractCollection.toString() String s = (e == c) ? "(this Collection)" : objectToString(e); a[i] = s; charLength += s.length();    }    return toString(a, size, charLength);}/** * 与 Arrays.toString() 类似,但调用者保证 size > 0,索引为 0 <= i < size 的每 * 个元素都是非空 String,charLength 是输入 String 的长度之和。 */static String toString(Object[] a, int size, int charLength) {    // assert a != null;    // assert size > 0;    // Copy each string into a perfectly sized char[]    // Length of [ , , , ] == 2 * size    final char[] chars = new char[charLength + 2 * size];    chars[0] = '[';    int j = 1;    for (int i = 0; i < size; i++) { if (i > 0) {     chars[j++] = ',';     chars[j++] = ' '; } String s = (String) a[i]; int len = s.length(); s.getChars(0, len, chars, j); j += len;    }    chars[j] = ']';    // assert j == chars.length - 1;    return new String(chars);}

整个过程中就是将当前状态队列的元素进行拼接输出,而不会影响到其他线程操作队列,只是在通过toArray()获取队列元素的时候进行加锁。

看看Java8是怎么写的:

public String toString() {    fullyLock();    try { Node<E> p = head.next; if (p == null)     return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) {     E e = p.item;     sb.append(e == this ? "(this Collection)" : e);     p = p.next;     if (p == null)  return sb.append(']').toString();     sb.append(',').append(' '); }    } finally { fullyUnlock();    }}

Java8中,toString输出字符串在前面加了一个锁fullyLock(),fullyLock()使用ReentrantLock对put和take、poll分别加锁。

Java8会在整个toString的拼接过程中,对队列进行加锁,会影响性能。

private final ReentrantLock takeLock = new ReentrantLock();private final ReentrantLock putLock = new ReentrantLock();void fullyLock() {    putLock.lock();    takeLock.lock();}

总结

简单点说

Java8中的toString,就如同一个人干活,一群人歇下来看着他干完完,比较粗暴。
在这里插入图片描述
Java11中是:

toString():我要输出了,队列你先把当前值给我

队列:放下原来的事,把toString()要的数据准备好,给了toString()后,继续做原来的事

toString:我可以输出了
在这里插入图片描述
我想这应该是很好理解的。

开发者涨薪指南 《从Java面试题看源码》-Java11中的toString与Java8的区别 48位大咖的思考法则、工作方式、逻辑体系