By Peter Lawrey

https://www.voxxed.com/blog/2014/12/how-and-why-unsafe-is-used-in-java/

Overview

sun.misc.Unsafe has been in Java from at least as far back as Java 1.4 (2004).  In Java 9, Unsafe will be hidden along with many other, for-internal-use classes. to improve the maintainability of the JVM.  While it is still unclear exactly what will replace Unsafe, and I suspect it will be more than one thing which replaces it, it raises the question, why is it used at all?

Doing things which the Java language doesn’t allow but are still useful.

Java doesn’t allow many of the tricks which are available to lower level languages.  For most developers this is very good thing, and it not only saves you from yourself, it also saves you from your co-workers.  It also makes it easier to import open source code because you know there is limits to how much damage they can do.  Or at least there is limits to how much you can do accidentally. If you try hard enough you can still do damage.

But why would you even try, you might wonder?  When building libraries many (but not all) of the methods in Unsafe are useful and in some cases, there is no other way to do the same thing without using JNI, which is even more dangerous and you lose the “compile once, run anywhere”

Deserialization of objects

When deserializing or building an object using a framework, you make the assumption you want to reconstitute an object which existed before.  You expect that you will use reflection to either call the setters of the class, or more likely set the internal fields directly, even the final fields.  The problem is you want to create an instance of an object, but you don’t really need a constructor as this is likely to only make things more difficult and have side effects.
1
2
3
4
5
6
7
8
9
10
11
public class A implements Serializable {
    private final int num;
    public A(int num) {
        System.out.println("Hello Mum");
        this.num = num;
    }
 
    public int getNum() {
        return num;
    }
}

In this class, you should be able to rebuild and set the final field, but if you have to call a constructor and it might do things which don’t have anything to do with deserialization.  For these reasons many libraries use Unsafe to create instances without calling a constructor

1
2
3
Unsafe unsafe = getUnsafe();
Class aClass = A.class;
A a = (A) unsafe.allocateInstance(aClass);

Calling allocateInstance avoids the need to call the appropriate constructor, when we don’t need one.

Thread safe access to direct memory

Another use for Unsafe is thread safe access to off heap memory.  ByteBuffer gives you safe access to off heap or direct memory, however it doesn’t have any thread safe operations.  This is particularly useful if you want to share data between processes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;
 
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
 
public class PingPongMapMain {
    public static void main(String... args) throws IOException {
        boolean odd;
        switch (args.length < 1 ? "usage" : args[0].toLowerCase()) {
            case "odd":
                odd = true;
                break;
            case "even":
                odd = false;
                break;
            default:
                System.err.println("Usage: java PingPongMain [odd|even]");
                return;        }
        int runs = 10000000;
        long start = 0;
        System.out.println("Waiting for the other odd/even");
        File counters = new File(System.getProperty("java.io.tmpdir"), "counters.deleteme");        counters.deleteOnExit();
 
        try (FileChannel fc = new RandomAccessFile(counters, "rw").getChannel()) {
            MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
            long address = ((DirectBuffer) mbb).address();
            for (int i = -1; i < runs; i++) {
                for (; ; ) {
                    long value = UNSAFE.getLongVolatile(null, address);
                    boolean isOdd = (value & 1) != 0;
                    if (isOdd != odd)
                        // wait for the other side.
                        continue;
                    // make the change atomic, just in case there is more than one odd/even process
                    if (UNSAFE.compareAndSwapLong(null, address, value, value + 1))
                        break;
                }
                if (i == 0) {
                    System.out.println("Started");
                    start = System.nanoTime();
                }
            }
        }
        System.out.printf("... Finished, average ping/pong took %,d ns%n",
                (System.nanoTime() - start) / runs);
    }
 
    static final Unsafe UNSAFE;
 
    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            UNSAFE = (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

When you run this in two programs, one with odd and the other with even. You can see that each process is changing data via  persisted shared memory.

In each program it maps the same are of the disks cache into the process.  There is actually only one copy of the file in memory.  This means the memory can be shared, provided you use thread safe operations such as the volatile and CAS operations.

The output on an i7-3970X is

Waiting for the other odd/even
Started
… Finished, average ping/pong took 83 ns

That is 83 ns round trip time between two processes. When you consider System V IPC takes around 2,500 ns and IPC volatile instead of persisted, that is pretty quick.

Is using Unsafe suitable for work?

I wouldn’t recommend you use Unsafe directly.  It requires far more testing than natural Java development.  For this reason I suggest you use a library where it’s usage has been tested already.  If you wan to use Unsafe yourself, I suggest you thoughly test it’s usage in a stand alone library.  This limits how Unsafe is used in your application and give syou a safer, Unsafe.

Conclusion

It is interesting that Unsafe exists in Java, and you might to play with it at home.  It has some work applications especially in writing low level libraries, but in general it is better to use a library which uses Unsafe which has been tested than use it directly yourself.

How and Why Unsafe is Used in Java---reference的更多相关文章

  1. Java Reference核心原理分析

    本文转载自Java Reference核心原理分析 导语 带着问题,看源码针对性会更强一点.印象会更深刻.并且效果也会更好.所以我先卖个关子,提两个问题(没准下次跳槽时就被问到). 我们可以用Byte ...

  2. Java Reference简要概述

    @(Java)[Reference] Java Reference简要概述 Reference对象封装了其它对象的引用,可以和普通的对象一样操作. Java提供了四种不同类型的引用,引用级别从高到低分 ...

  3. Java Reference 源码分析

    @(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...

  4. java Reference

    相关讲解,参考: Java Reference 源码分析 Java Reference详解 Reference: // 名称说明下:Reference指代引用对象本身,Referent指代被引用对象 ...

  5. Java Reference & ReferenceQueue一览

    Overview The java.lang.ref package provides more flexible types of references than are otherwise ava ...

  6. Implementing the skip list data structure in java --reference

    reference:http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Map/skip-list-impl.html The link ...

  7. 理解java reference

    Java世界泰山北斗级大作<Thinking In Java>切入Java就提出“Everything is Object”.在Java这个充满Object的世界中,reference是一 ...

  8. What Influences Method Call Performance in Java?--reference

    reference from:https://www.voxxed.com/blog/2015/02/too-fast-too-megamorphic-what-influences-method-c ...

  9. Why String is immutable in Java ?--reference

    String is an immutable class in Java. An immutable class is simply a class whose instances cannot be ...

  10. java Reference(摘录)

    Java中的Reference对象和GC是紧密联系在一起的,Reference的实现也是和GC相关的. 强引用 强引用是Java中使用最普遍的引用,我们经常使用的Object o = new Obje ...

随机推荐

  1. bzoj 3053 HDU 4347 : The Closest M Points kd树

    bzoj 3053 HDU 4347 : The Closest M Points  kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...

  2. NOIP 2011 提高组 计算系数

    有二项式定理 `\left( a+b\right) ^{n}=\sum _{r=0}^{n}\left( \begin{matrix} n\\ r\end{matrix} \right) a^{n-r ...

  3. VirtualBox虚拟机中启用usb3.0却无法显示u盘的解决方法

    主机系统为win7 64位,由于工作需要,安装了Virtualbox 5.18虚拟机,virtaulbox中安装了win7 32系统.以为下启用usb 3.0的步骤: 1.宿主机要支持 usb 3.0 ...

  4. Programming in lua 环境

    Lua 用一个名为environment 普通的表来保存所有的全局变量.(更精确的说,Lua在一系列的environment 中保存他的“global”变量,但是我们有时候可以忽略这种多样性)这种结果 ...

  5. 【HDOJ】3315 My Brute

    几乎与2853相同,MCMF. /* 2853 */ #include <iostream> #include <string> #include <map> #i ...

  6. windows下 破解 Sublime Text3 和汉化

    这货已经出到3了. windows下载,破解,使用方法: 一:破解 1: 去官网下载最新版本 http://www.sublimetext.com/3 2:下载破解器(SublimeTextKeyge ...

  7. [转]Oracle查询树形数据的叶节点和子节点

    oracle 9i判断是叶子或根节点,是比较麻烦的一件事情,SQL演示脚本如下: --表结构-- DROP TABLE idb_hierarchical; create TABLE idb_hiera ...

  8. 生成AWK快照的方法

    1.首先在用oracle用户登陆执行sqlplus命令用dba用户执行: exec DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT (flush_level=> ...

  9. Windows Phone SDK 8.0 安装系统要求

    Windows Phone SDK 8.0 是一个功能齐全的开发环境,可用于构建 Windows Phone 8.0 和 Windows Phone 7.5 的应用和游戏. Windows Phone ...

  10. Linux学习笔记32——select()函数分析【转】

    Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如 connect.accept.recv或recvfrom这样的阻塞程序 ...