Java|Java中的天使和魔鬼:Unsafe类( 四 )


这种序列化方式是非常快的 。
12、大数组如你所知Java数组长度的最大值是Integer.MAX_VALUE 。 使用直接内存分配我们可以创建非常大的数组 , 该数组的大小只受限于堆的大小 。
这里有一个SuperArray的实现:
一个简单的用法:
事实上该技术使用了非堆内存off-heap memory , 在 java.nio 包中也有使用 。
通过这种方式分配的内存不在堆上 , 并且不受GC管理 。 因此需要小心使用Unsafe.freeMemory() 。 该方法不会做任何边界检查 , 因此任何不合法的访问可能就会导致JVM崩溃 。
这种使用方式对于数学计算是非常有用的 , 因为代码可以操作非常大的数据数组 。 同样的编写实时程序的程序员对此也非常感兴趣 , 因为不受GC限制 , 就不会因为GC导致非常大的停顿 。
13、并发关于并发编程使用Unsafe的只言片语 。 compareAndSwap 方法是原子的 , 可以用来实现高性能的无锁化数据结构 。
举个例子 , 多个线程并发的更新共享的对象这种场景:
首先我们定义一个简单的接口 Counter:
我们定义工作线程 CounterClient 它会使用 Counter:
这是测试代码:
第一个实现-没有同步的计数器:
输出:
速度很多 , 但是没有对所有的线程进行协调所以结果是错误的 。 第二个版本 , 使用Java常见的同步方式来实现
输出:
彻底的同步当然会导致正确的结果 。 但是花费的时间令人沮丧 。 让我们试试 ReentrantReadWriteLock:
输出:
结果依然是正确的 , 时间也短 。 那使用原子的类呢?
输出:
使用AtomicCounter的效果更好一点 。 最后我们试试Unsafe的原子方法compareAndSwapLong看看是不是更进一步 。
输出:
看起来和使用原子类是一样的效果 , 难道原子类使用了Unsafe?答案是YES 。
事实上该例子非常简单但表现出了Unsafe的强大功能 。
就像前面提到的 CAS原语可以用来实现高效的无锁数据结构 。 实现的原理很简单:
1、拥有一个状态;
2、创建一个它的副本;
3、修改该副本;
4、执行 CAS 操作;
5、如果失败就重复执行;
事实上 , 在真实的环境它的实现难度超过你的想象 , 这其中有需要类似ABA , 指令重排序这样的问题 。
14、结论尽管Unsafe有这么多有用的应用 , 但是尽量不要使用 。 当然了使用JDK中利用了Unsafe实现的类是可以的 。 或者你对你代码功力非常自信 , 可以自己挖坑再填坑哈~
欢迎小伙伴们留言交流~~