Java8 中不起眼的新特性

jopen 9年前

Metaspace

 一直以来,JVM 都在heap 中管理这一个称为PermGen的区域,用于放置Class对象实例, 静态变量, String pool等。PermGen的存在对于GC 有很大的影响,存在于PermGen 中的对象很少能被回收,一旦PermGen 满了就会触发Stop-the-world 的Full GC——即使是设置使用了CMS 等延迟更低的垃圾收集器也是如此。一旦垃圾回收也不能会受到足够的内存,OOM Error就会被引发,终止程序的执行。使用了动态字节码生产技术的时候(asm, 动态代理, groovy等),由于需要生产很多动态类,这种情况更为严重。

在Java7 中, String pool 被移出了PermGen。到了Java8,PermGen 被彻底取消,Class 对象等元数据被放到了新的空间Metaspace 中。Metaspace 不存在于JVM Heap中,不受GC 管辖,也降低了GC 的压力。由于只存储class 元数据,所以数据的移除策略也很简单,当没有这个class 的实例存在后,就可以移除。

64位的server JVM 中,Metaspace 初始大小为21M。当Metaspace 满了之后,依然会触发GC,同时会调大Metaspace 空间。如果必要的话,可以通过–XX:MetaspaceSize 来设置初始的大小,避免引发GC。

Stamped Locks

时间戳锁。时间戳锁是一种乐观锁,它维持一个序号,每个更新操作都会将将序号增加。在起始的时候,记录一个序号,在访问完成之后,如果这个序号没有改变,就认为这段时间没有访问冲突。这是一种性能极高的加锁方式。

long stamp = lock.tryOptimisticRead();  work;  if (lock.validate(stamp)){     //success! no contention with a writer thread   } else {     // 访问冲突, 直接fail back 到普通的锁     stamp = lock.readLock();     try {         //no writing happening now         work();     } finally {          lock.unlock(stamp);      }  } 

Concurrent Adders

Concurrent Adders 是Atomic类的进化版本。原子类通过不断的cas 自旋,来实现原子的更新。如果竞争激烈的情况下,会一直进行cas  操作直到成功,消耗CPU 资源。

Concurrent Adders 为每个线程保存一个本地的增量。在cas 自旋失败之后,直接将要add 的增量写到线程本地的增量中。当要读取的时候,在取出数据的基础上,再加上本线程以及其他线程的增量,从而得到一个最终正确的数值。

除非有特殊原因,使用Concurrent Adders 代替原子类是一个很好的选择。

Parallel Sorting

增加了充分利用多核的排序方法:

Arrays.parallelSort(myArray);
String Joiner
Java中终于有对String join 的支持了,Java 8 中增加了StringJoiner 类:
String joined = new StringJoiner("-")      .add("foo")      .add("bar")      .add("baz")      .toString(); // "foo-bar-baz"

</div> Optional References

这个是从scala 等函数式编程语言借鉴来的东西,在函数式编程语言中,Optional 用来消除null 引起的副作用,是一种Monad 的方式。Guava 等lib 已经有了类似的工具,现在Java 把它引入到了标准库中。Optional 是一个泛型类,它可以hold一个null 或者非null 的value,提供get(), orElse(), ifPresent() 等方法。

Optional<User> user = tryFindUser(int userID);  user.ifPresent(System.out::print);

</div>

原文链接: http://www.dongliu.net/post/5226880978386944