您的位置:首页 > Web前端

Java --- Unsafe

2015-10-09 16:19 459 查看

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
*/
privatevoid
unparkSuccessor(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 (Node
t = 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, Object
k) {
if (k !=
null) {
for (Node<K,V>
e = first;
e != null;
e = e.next) {
ints; K
ek;
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
{
Thread
w;
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 in
lw ^ 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));
}
}

// The
epilogue 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.Unsafe
getUnsafe() {
try {
return sun.misc.Unsafe.getUnsafe();
} catch (SecurityException
tryReflectionInstead) {}
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.Field
f : k.getDeclaredFields()) {

f.setAccessible(true);

Object x = f.get(null);

if (k.isInstance(x))

returnk.cast(x);
}
thrownew NoSuchFieldError("the Unsafe");
}});
} catch (java.security.PrivilegedActionException
e) {
thrownew RuntimeException("Could not initialize
intrinsics",
e.getCause());
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: