- 关于反射,两个最让人郁闷的地方都修正了
旧版JDK,反射时可能抛出ClassNotFoundException、NoSuchMethodException、IllegalAccessException还有InvocationTargetExcetpion,不知道别人怎样,反正我肯定会很偷懒的只捕捉或声明Exception类了,虽然可能有一百个理由说这样不好。JDK7之后,这堆异常有了叫ReflectiveOperationExcetpion的父类,抓它就行。
旧版JDK,还有个很莫名其妙的地方,就是所有反射,都拿不到参数名,无论名字叫啥,都返回arg0,arg1,所以在CXF,SpringMVC里,你都要把参数名字用annotation再写一遍:
Person getEmployee(@PathParam(“dept”) Long dept, @QueryParam(“id”) Long id)
现在,JDK8新提供的类java.lang.reflect.Parameter可以反射参数名了,编译时要加参数,如 javac -parameters xxx.java,或者Eclipse里设置。然后就可以写成:
Person getEmployee(@PathParam Long dept, @QueryParam Long id)
比AtomicLong更好的高并发计数器
在超高并发的场景下,AtomicLong其实没有银弹,虽然没有锁,一样要通过不停循环的CAS来解决并发冲突。for ( ; ; ) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return next;
}
可见,如果并发很高,每条线程可能要转好几轮的compareAndSet()才把自己的increment()做了。
那这时候,是不是会想起ConcurrentHashMap,分散开十六把锁来分散冲突概率的模式?
JDK8新增了一个LongAdder来实现这个思路,内部有多个计数器,每次increment()会落到其中一个计数器上,到sum()的时候再把它们的值汇总。
没有JDK8的同学也没所谓,Guava把LongAdder拷贝了一份。
但注意,此计数器适合高并发地increment(),到了某个时刻才sum()一次的统计型场景,如果要频繁、高并发地查询计数器的当前值,分散计数器带来的好处就抵消了。
另外,它的实现也比AtomicLong复杂不少,如果并发度不是那么高,继续用AtomicLong其实也挺好,简单就是好。
PS. 在酷壳有一篇更详细的讲解:<从LongAdder看更高效的无锁实现>
- JDK7/8中排序算法的改进
面试季的同学背一脑袋的插入、归并、冒泡、快排,那,JDK到底看上了哪家的排序算法?
Colletions.sort(list) 与 Arrays.sort(T[])
Colletions.sort()实际会将list转为数组,然后调用Arrays.sort(),排完了再转回List。
PS. JDK8里,List有自己的sort()方法了,像ArrayList就直接用自己内部的数组来排,而LinkedList, CopyOnWriteArrayList还是要复制出一份数组。
而Arrays.sort(),对原始类型(int[],double[],char[],byte[]),JDK6里用的是快速排序,对于对象类型(Object[]),JDK6则使用归并排序。为什么要用不同的算法呢?
JDK7的进步
到了JDK7,快速排序升级为双基准快排(双基准快排 vs 三路快排);归并排序升级为归并排序的改进版TimSort,一个JDK的自我进化。
JDK8的进步
再到了JDK8, 对大集合增加了Arrays.parallelSort()函数,使用fork-Join框架,充分利用多核,对大的集合进行切分然后再归并排序,而在小的连续片段里,依然使用TimSort与DualPivotQuickSort。
结论
JDK团队的努力,从一些简单的New Features / Change List 根本看不到,所以没事升级一下JDK还是好的…..
高并发的ThreadLocalRandom
JDK7的Concurrent包里有一个ThreadLocalRandom,伪随机数序列的算法和父类util.Random一样,遵照高德纳老爷子在《The Art of Computer Programming, Volume 2》里说的:x(0)=seed;
x(i+1)=(A* x(i) +B) mod M;
区别是Random里的seed要用到AtomicLong,还要经常compareAndSet(current, next)来避免并发冲突,而ThreadLocalRandom用ThreadLocal模式来解决并发问题,seed用long就行了。
用法: int r = ThreadLocalRandom.current() .nextInt(1000);
没有JDK7的,可自行Copy Paste这个类,Netty和Esper都是这么干的。
ImportNews翻译了一篇更详细的文章: 多线程环境下生成随机数
- JDK7
JDK6好像终于混不下去了,Spring Boot 1.2带的Tomcat和Jetty都要JDK7才能跑。没有用spring boot的Parent的话,要把Tomcat版本降下去挺麻烦的。另外JavaSimon的4.0版也需要JDK7了。
发现新JDK无论吸引人与否,比如JDK8y有了种种突破,最终还是靠Big Player的框架类库决然升级才能带动开发者的升级。而Big Player们又在担心如果升级了会丢失一些无法升级的用户…..麻杆打狼两头怕。
- 《写给大忙人看的Java SE 8》
《写给大忙人看的Java SE 8》 :Java8的改进太大, 值得《Core Java》的作者再码一本, 事实上,为了保持兼容性,很多代码都保持在JDK5/6的水平上,这本书一次过将JDK7/JDK8的更新讲了,是本快捷的升级指南。
- Nashorn
Nashorn——在JDK 8中融合Java与JavaScript之力: JDK8的新JavaScript引擎据说是JDK6时的2-10倍,另外Avatar.js可以在Java里跑Node.js及其类库, 然后Node.js里又再调用Java的类库,纸包鸡包纸。