`

Java 8无人谈及的八大功能

阅读更多

时间戳锁

一直以来,多线程代码是服务器开发人员的毒药(问问Oracle的Java语言架构师和并行开发大师Brian Goetz)。Java的核心库不断加入各种复杂的用法来减少访问共享资源时的线程等待时间。其中之一就是经典的读写锁(ReadWriteLock), 它让你把代码分成两部分:需要互斥的写操作和不需要互斥的读操作。

表面上看起来很不错。问题是读写锁有可能是极慢的(最多10倍),这已经和它的初衷相悖了。Java 8引入了一种新的读写锁——叫做时间戳锁。好消息是这个家伙真的非常快。坏消息是它使用起来更复杂,有更多的状态需要处理。并且它是不可重入的,这意味着 一个线程有可能跟自己死锁。

时间戳锁有一种“乐观”模式,在这种模式下每次加锁操作都会返回一个时间戳作为某种权限凭证;每次解锁操作都需要提供它对应的时间戳。如果一个线程 在请求一个写操作锁的时候,这个锁碰巧已经被一个读操作持有,那么这个读操作的解锁将会失效(因为时间戳已经失效)。这个时候应用程序需要从头再来,也许 要使用悲观模式的锁(时间戳锁也有实现)。你需要自己搞定这一切,并且一个时间戳只能解锁它对应的锁——这一点必须非常小心。

下面我们来看一下这种锁的实例——

long stamp = lock.tryOptimisticRead(); // 非阻塞路径——超级快
work(); // 我们希望不要有写操作在这时发生
if (lock.validate(stamp)){
       //成功!没有写操作干扰 
}
else {
       //肯定同时有另外一个线程获得了写操作锁,改变了时间戳
       //懒汉说——我们切换到开销更大的锁吧
	
            stamp = lock.readLock(); //这是传统的读操作锁,会阻塞
       try {
                 //现在不可能有写操作发生了
                 work();

       }
       finally {
            lock.unlock(stamp); // 使用对应的时间戳解锁
       }
}

并发加法器

Java 8另一个出色的功能是并发“加法器”,它对大规模运行的代码尤其有意义。一种最基本的并发模式就是对一个计数器的读写。就其本身而言,现今处理这个问题有很多方法,但是没有一种能比Java 8提供的方法高效或优雅。

到目前为止,这个问题是用原子类(Atomics)来解决的,它直接利用了CPU的“比较并交换”指令(CAS)来测试并设置计数器的值。问题在于 当一条CAS指令因为竞争而失败的时候,AtomicInteger类会死等,在无限循环中不断尝试CAS指令,直到成功为止。在发生竞争概率很高的环境 中,这种实现被证明是非常慢的。

来看Java 8的LongAdder。这一系列类为大量并行读写数值的代码提供了方便的解决办法。使用超级简单。只要初始化一个LongAdder对象并使用它的add()和intValue()方法来累加和采样计数器。

这和旧的Atomic类的区别在于,当CAS指令因为竞争而失败时,Adder不会一直占着CPU,而是为当前线程分配一个内部cell对象来存储 计数器的增量。然后这个值和其他待处理的cell对象一起被加到intValue()的结果上。这减少了反复使用CAS指令或阻塞其他线程的可能性。

如果你问你自己,什么时候应该用并发加法器而不是原子类来管理计数器?简单的答案就是——一直这么做。

并行排序

正像并发加法器能加速计数一样,Java 8还实现了一种简洁的方法来加速排序。这个秘诀很简单。你不再这么做:

Array.sort(myArray);

而是这么做:

Arrays.parallelSort(myArray);

这会自动把目标数组分割成几个部分,这些部分会被放到独立的CPU核上去运行,再把结果合并起来。这里唯一需要注意的是,在一个大量使用多线程的环境中,比如一个繁忙的Web容器,这种方法的好处就会减弱(降低90%以上),因为越来越多的CPU上下文切换增加了开销。

切换到新的日期接口

Java 8引入了全新的date-time接口。当前接口的大多数方法都已被标记为deprecated,你就知道是时候推出新接口了。新的日期接口为Java核 心库带来了易用性和准确性,而以前只能用Joda time才能达到这样的效果(译者注:Joda time是一个第三方的日期库,比Java自带的库更友好更易于管理)。

跟任何新接口一样,好消息是接口变得更优雅更强大。但不幸的是还有大量的代码在使用旧接口,这个短时间内不会有改变。

为了衔接新旧接口,历史悠久的Date类新增了toInstant()方法,用于把Date转换成新的表示形式。当你既要享受新接口带来的好处,又要兼顾那些只接受旧的日期表示形式的接口时,这个方法会显得尤其高效。

控制操作系统进程

想在你的代码里启动一个操作系统进程,通过JNI调用就能完成——但这个东西总令人一知半解,你很有可能得到一个意想不到的结果,并且一路伴随着一些很糟糕的异常。

即便如此,这是无法避免的事情。但进程还有一个讨厌的特性就是——它们搞不好就会变成僵尸进程。目前从Java中运行进程带来的问题是,进程一旦启动就很难去控制它。

为了帮我们解决这个问题,Java 8在Process类中引入了三个新的方法

  1. destroyForcibly——结束一个进程,成功率比以前高很多。
  2. isAlive——查询你启动的进程是否还活着。
  3. 重载了waitFor(),你现在可以指定等待进程结束的时间了。进程成功退出后这个接口会返回,超时的话也会返回,因为你有可能要手动终止它。

这里有两个关于如何使用这些新方法的好例子——

  • 如果进程没有在规定时间内退出,终止它并继续往前走。
if (process.wait(MY_TIMEOUT, TimeUnit.MILLISECONDS)){
//成功 }
else {
process.destroyForcibly();
}
  • 在你的代码结束前,确保所有的进程都已退出。僵尸进程会逐渐耗尽系统资源。
for (Process p : processes) {
       if (p.isAlive()) {
             p.destroyForcibly();
       }
}

精确的数字运算

数字溢出会导致一些讨厌的bug,因为它本质上不会出错。在一些系统中,整型值不停地增长(比如计数器),溢出的问题就尤为严重。在这些案例里面, 产品在演进阶段运行得很好,甚至商用后的很长时间内也没问题,但最终会出奇怪的故障,因为运算开始溢出,产生了完全无法预料的值。

为了解决这个问题,Java 8为Math类添加了几个新的“精确型”方法,以便保护重要的代码不受溢出的影响,它的做法是当运算超过它的精度范围的时候,抛出一个未检查的ArithmeticException异常。

int safeC = Math.multiplyExact(bigA, bigB); 
// 如果结果超出+-2^31,就会抛出ArithmeticException异常

唯一不好的地方就是你必须自己找出可能产生溢出的代码。无论如何,没有什么自动的解决方案。但我觉得有这些接口总比没有好。

安全的随机数发生器

在过去几年中Java一直因为安全漏洞而饱受诟病。无论是否合理,Java已经做了大量工作来加强虚拟机和框架层,使之免受攻击。如果随机数来源于随机性不高的种子,那么那些用随机数来产生密钥或者散列敏感信息的系统就更易受攻击。

到目前为止,随机数发生算法由开发人员来决定。但问题是,如果你想要的算法依赖于特定的硬件、操作系统、虚拟机,那你就不一定能实现它。这种情况下,应用程序倾向于使用更弱的默认发生器,这就使他们暴露在更大的风险下了。

Java 8添加了一个新的方法叫SecureRandom.getInstanceStrong(),它的目标是让虚拟机为你选择一个安全的随机数发生器。如果你 的代码无法完全掌控操作系统、硬件、虚拟机(如果你的程序部署到云或者PaaS上,这是很常见的),我建议你认真考虑一下使用这个接口。

可选引用

空指针就像“踢到脚趾”一样——从你学会走路开始就伴随着你,无论现在你有多聪明——你还是会犯这个错。为了帮助解决这个老问题,Java 8引入了一个新模板叫Optional<T>。

这个模板是从Scala和Hashkell借鉴来的,用于明确声明传给函数或函数返回的引用有可能是空的。有了它,过度依赖旧文档或者看过的代码经常变动的人,就不需要去猜测某个引用是否可能为空。

Optional<User> tryFindUser(int userID) {

void processUser(User user, Optional<Cart> shoppingCart) {

Optional模板有一套函数,使得采样它更方便,比如isPresent()用来检查这个值是不是非空,或者ifPresent()你可以传递 一个Lambda函数过去,如果isPresent()返回true,这个Lambda函数就会被执行。不好的地方就跟Java 8的新日期接口一样,等这种模式逐渐流行,渗透到我们使用的库中和日常设计中,需要时间和工作量。

用新的Lambda语法打印Optional值:

value.ifPresent(System.out::print);
分享到:
评论

相关推荐

    Java字节码转换工具—Retrotranslator

    Retrotranslator的网站位于http: //sourceforge.net/projects/retrotranslator,可以在这个网站下载相关的...当 然,该工具也不是完全可以兼容jdk15的新功能,在其网站上面也谈及了不能够实现的部分,可以作为参考。

    JAVA(高级教程)

    上次的教程中还没有来得及谈及的问题。我还将向你们展示 Javascript的许多神奇功能,使你能够制作真正对多媒体应用 程序。 以下是我们将涉及的内容: • 给变量赋值 • If-then语句 • For和while循环 • 编写你...

    古今中外著名算题趣谈及详解

    古今中外著名算题趣谈及详解

    高考图文转换题例谈及训练作文.doc

    高考图文转换题例谈及训练作文.doc

    Java项目如何进行性能优化

    当我们谈及性能,最直观能想到的一个词是“快”,哪到底怎么才是快呢?如何又为慢! 02-什么样的体验叫快呢? 3S定理:Strangeloop在对众多的网站做性能分析之后得出了一个著名的3s定律“页面加载速度超过3s,57%的...

    Windows 8:十大值得关注的功能

    在Windows 8首次展示之际,IT人员就已经开始头疼系统升级、系统迁移、...大家关注了很多的功能,但笔者总结了以下十个很少被谈及的功能,并相信如果你使用了这些功能,会从中受益的。  1.快速启动  通过笔者的计

    基础电子中的Windows 8:十大值得关注的功能

    在Windows 8首次展示之际,IT人员就已经开始头疼系统升级、系统迁移、系统...大家关注了很多的功能,但笔者总结了以下十个很少被谈及的功能,并相信如果你使用了这些功能,会从中受益的。  1.快速启动  通过笔者的

    流动性洞见系列三:当我们谈及流动性的时候,我们在说什么?.pdf

    流动性洞见系列三:当我们谈及流动性的时候,我们在说什么?.pdf

    磨剑系列专题报告:谈及财政预算时,需要知道哪些?(2020)(19页).pdf

    磨剑系列专题报告:谈及财政预算时,需要知道哪些?(2020)(19页).pdf

    JAVA操作XMLDOM4j简单教程1

    DOM4J使用起来非常简单。只要你了解基本的XML-DOM模型,就能使用。...国内的中文资料很少。因而俺写这个短小的教程方便大家使用,这篇文章仅谈及基本的用法,如需深入的使用,请……自己摸索或查找别的资料。

    网上投递简历的经验之谈及心得

    总结了网投简历的一些研究心得,很有用的东西哦

    Java比较C#胜在何处

     后来渐渐参与各种项目,工作,等等原因,在初的7年中主要的开发语言是c++/c#,在这篇文章中我不想谈及c++,因为我在以往的博文中已经有很多这方面的随笔。虽然当时c#是我的主要开发语言,但是对于Java的每次重大...

    您的JAVA代码安全吗?

    虽然客户仍然很关心您为他们构建的应用程序的可伸缩性和可用性,但他们可能变得也很关心安全性,而且要求特别严格。应用程序可能容易受到两...这里在谈到Java安全性时,我们并不谈及Java语言提供的安全性API,也不涉及

    网站策划之网站要素:内容、功能、表现

    网站的本质就是形式主义,内容、功能、表现这三个网站的要素,低保真原型解决了基础内容层面的问题,而高保真线框图规划了网站的功能和表现;内容是网站最基本最重要的核心,因此高保真原型必须建立在低保真原型的...

    Dom4j是一个易用的、开源的库

    DOM4J是dom4j.org出品的一个开源XML解析包,它的网站中这样定义: Dom4j is an easy to use, open source ...因而俺写这个短小的教程方便大家使用,这篇文章仅谈及基本的用法,如需深入的使用,可以查找别的资料。

    XYXDBP-WGP#Effective-Java#第35条:用实例域代替序数 a0557a2543f4441a8823d6c3

    永远不要根据枚举的序数导出与它关联的值,而是要将它保存在一个实例域中:public enum Ensemble {Enum规范中谈及ordinal方法时写道:

    开源XML解析包dom4j

    一个很好的用来解析XML文件的解析包 DOM4J是dom4j.org出品的一个开源XML解析包,它的网站中这样...因而俺写这个短小的教程方便大家使用,这篇文章仅谈及基本的用法,如需深入的使用,请……自己摸索或查找别的资料。

    IE网页图片浏览器(ImageBrowser) v1.0

    Imagebrowser可以将当前网页中所包含的图片、链接指向的图片甚至谈及到的图片全部进行集中小图目录显示,点击小图片方便的浏览大图。可以过滤显示图片的种类和图片文件大小。可在收藏夹收藏图片及原网页地址。适用:...

    HTML5与Flash对比

    从大量的报道中,如果各位从Google搜索引擎中输入“HTML5 Flash”这2个关键字组合,将会有1百多万条相关的资讯,真是犹如狂风暴雨一般,而现在的IE8,Safari 4和FF 3.5 RC都或多或少的支持了一些HTML5的功能,这就让...

Global site tag (gtag.js) - Google Analytics