Java --- Unsafe
来源:互联网 发布:c语言创建线程 编辑:程序博客网 时间:2024/06/05 09:23
Java --- Unsafe
初步介绍
在AQS,Netty和Guava的源码中出现了sun.misc.Unsafe 的身影。Unsafe类的定义是:执行底层,不安全的操作的方法的集合,所有的方法都是Native的。主要分为以下几类方法:
内存操作:
addressSize,allocateMemory,copyMemory,copyMemory,freeMemory,getAddress,putAddress,reallocateMemory,setMemory,setMemory,pageSize,
实例域或静态域操作:
fieldOffset,getBoolean,getBoolean,getBooleanVolatile,getByte,getByte,getByte,getByteVolatile,getChar,getChar,getChar,getCharVolatile,getDouble,getDouble,getDouble,getDoubleVolatile,getFloat,getFloat,getFloat,getFloatVolatile,getInt,getInt,getInt,getIntVolatile,getLong,getLong,getLong,getLongVolatile,getObject,getObject,getObjectVolatile,getShort,getShort,getShort,getShortVolatile,objectFieldOffset,putBoolean,putBoolean,putBooleanVolatile,putByte,putByte,putByte,putByteVolatile,putChar,putChar,putChar,putCharVolatile,putDouble,putDouble,putDouble,putDoubleVolatile,putFloat,putFloat,putFloat,putFloatVolatile,putInt,putInt,putInt,putIntVolatile,putLong,putLong,putLong,putLongVolatile,putObject,putObject,putObjectVolatile,putOrderedInt,putOrderedLong,putOrderedObject,putShort,putShort,putShort,putShortVolatile,staticFieldBase,staticFieldBase,staticFieldOffset,compareAndSwapInt,compareAndSwapLong,compareAndSwapObject,
线程操作:
Park,unpark
类和对象操作:
defineAnonymousClass,defineClass,defineClass,ensureClassInitialized,allocateInstance,
其它(对象锁,获取负载均衡…):
monitorEnter,monitorExit,tryMonitorEnter,getLoadAverage,getUnsafe,throwException,arrayBaseOffset,arrayIndexScale,
这里把所有方法大概的列了一下,具体方法说明可以参见:
http://www.docjar.com/docs/api/sun/misc/Unsafe.html#monitorEnter%28Object%29
看了所有的方法后,可以发现操作大都是直接绕过虚拟机的规范限制而直接操作内存,这样没有了保护当然是Unsafe的了,但又一个重点是native,对于native的调用在字节码层面就是一个字节码,如果我们用Java语言来操作上面的比如域赋值等操作的话,最终的字节码是不止一个的,这样在多线程环境下就必须要进行同步保护了。
AQS中的Unsafe
AQS作为作为排外和共享锁的一个通用基类,再起FIFO队列操作中大量使用了Unsafe的compareAndSwapXXX方法进行队列操作,利用native方法的原子性来保证了线程安全。
/**
* CAS waitStatus field of a node.
*/
privatestaticfinalboolean compareAndSetWaitStatus(Node node,
intexpect,
intupdate) {
returnunsafe.compareAndSwapInt(node,waitStatusOffset,
expect, update);
}
/**
* CAS next field of a node.
*/
privatestaticfinalboolean compareAndSetNext(Node node,
Node expect,
Node update) {
returnunsafe.compareAndSwapObject(node,nextOffset,expect, update);
}
另外对堵塞等待的线程使用了unsafe的park和unpark来使得线程被挂起或获得执行的权限。
/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
privatevoidunparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
intws =node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node,ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s ==null ||s.waitStatus > 0) {
s =null;
for (Nodet = tail;t != null &&t != node;t = t.prev)
if (t.waitStatus <= 0)
s =t;
}
if (s !=null)
LockSupport.unpark(s.thread);
}
/**
* Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
privatefinalboolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
另外JDK concurrent的automD
Netty中的Unsafe
在Netty使用了Unsafe操作来作为原子操作。
Io.netty.util.inernal.chmv8.ConcurrentHashMapV8是一个线程安全的HashMap,代码中多次使用了Unsafe的compareAndSwapXXX方法来作为原子操作,提供线程安全性。
final Node<K,V> find(inth, Objectk) {
if (k !=null) {
for (Node<K,V>e = first;e != null;e = e.next) {
ints; Kek;
if (((s =lockState) & (WAITER|WRITER)) != 0) {
if (e.hash == h &&
((ek = e.key) ==k || (ek !=null &&k.equals(ek))))
returne;
}
elseif (U.compareAndSwapInt(this,LOCKSTATE,s,
s +READER)) {
TreeNode<K,V>r, p;
try {
p = ((r =root) == null ?null :
r.findTreeNode(h,k, null));
} finally {
Threadw;
intls;
do {}while (!U.compareAndSwapInt
(this,LOCKSTATE,
ls = lockState,ls - READER));
if (ls == (READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
returnp;
}
}
}
returnnull;
}
Guava的unsafe
Guava中的com.google.common.primitives.UnsignedByte类给我们展示了除了常用来作为原子操作的之外的另一个作用,将字符数组的比较转换为一次性比较8个字符的比较方法。
@Overridepublicint compare(byte[]left, byte[]right) {
intminLength = Math.min(left.length,right.length);
intminWords =minLength / Longs.BYTES;
/*
* Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a
* time is no slower than comparing 4 bytes at a time even on 32-bit.
* On the other hand, it is substantially faster on 64-bit.
*/
for (inti = 0; i < minWords * Longs.BYTES;i += Longs.BYTES) {
longlw =theUnsafe.getLong(left,BYTE_ARRAY_BASE_OFFSET + (long)i);
longrw =theUnsafe.getLong(right,BYTE_ARRAY_BASE_OFFSET + (long)i);
if (lw !=rw) {
if (BIG_ENDIAN) {
return UnsignedLongs.compare(lw,rw);
}
/*
* We want to compare only the first index where left[index] != right[index].
* This corresponds to the least significant nonzero byte inlw ^ rw, since lw
* and rw are little-endian. Long.numberOfTrailingZeros(diff) tells us the least
* significant nonzero bit, and zeroing out the first three bits of L.nTZ gives us the
* shift to get that least significant nonzero byte.
*/
intn = Long.numberOfTrailingZeros(lw ^ rw) & ~0x7;
return (int) (((lw >>> n) & UNSIGNED_MASK) - ((rw >>>n) & UNSIGNED_MASK));
}
}
// Theepilogue to cover the last (minLength % 8) elements.
for (inti = minWords * Longs.BYTES;i < minLength;i++) {
intresult = UnsignedBytes.compare(left[i],right[i]);
if (result != 0) {
returnresult;
}
}
returnleft.length -right.length;
}
}
需要使用Unsafe类吗
从这些源码库的代码中可以看出sun.misc.Unsafe类是一个非常强大的类,但必须意识到这同时是一个非常危险的类。作为个人基本原则是不直接使用该类(因为我们使用这些开源类库的同时也在间接使用了该类的强大功能,同时也避免了其不安全因素)。
Unsafe实例的获取方法:
privatestatic sun.misc.UnsafegetUnsafe() {
try {
return sun.misc.Unsafe.getUnsafe();
} catch (SecurityExceptiontryReflectionInstead) {}
try {
return java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run()throws Exception {
Class<sun.misc.Unsafe>k = sun.misc.Unsafe.class;
for (java.lang.reflect.Fieldf : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
returnk.cast(x);
}
thrownew NoSuchFieldError("the Unsafe");
}});
} catch (java.security.PrivilegedActionExceptione) {
thrownew RuntimeException("Could not initialize intrinsics",
e.getCause());
}
}
- Java --- Unsafe
- JAVA-Unsafe
- Java Unsafe
- Unsafe--Java中Unsafe类详解
- java 中的Unsafe
- Java中Unsafe类
- java 中的Unsafe
- java 中的Unsafe(转)
- Java。UnSafe类
- java 中的Unsafe
- java 中的Unsafe
- java 中的Unsafe
- Java sun.misc.Unsafe
- Java Unsafe 类
- Java JDK Unsafe
- java中的Unsafe
- java 中的Unsafe
- 关于Java Unsafe
- android关于GPS hal层的分析
- 大话计算机-计算机系统-硬件-控制器
- java中 implements Serializable时 报错 could not find class file 处理办法
- Java的List模板类型与C++的list模板类型的比较
- bpm算法+应用想法
- Java --- Unsafe
- jquery 实现 图片上传 预览
- .net面试题目
- shared libraries: libgtest.so.0: cannot open shared object fi
- GPS数据计算校验和的方法
- PHPSTORM/IntelliJ IDEA 常用 设置配置优化
- HealthKit框架参考
- 星级评定 swift
- 数据库范式真的很难吗?