一.CAS(compare and swap)
Unsafe 用于实现CAS(compare and swap) 操作,基于CPU一条原始指令,是原子的线程安全的,可用于多线程间非阻塞方式实现线程安全。
多线程中如果有多个线程修改共享变量,一般使用synchronized ,只有一个线程获得锁可以修改,其它线程阻塞等待锁释放, Unsafe.compareAndSwapXXX 使用比较再交换方式:
AbstractQueuedSynchronizer类中有实现:
private transient volatile Node tail;//volatile 用于可见性
private static final Unsafe unsafe = Unsafe.getUnsafe();//获取对象
static final long tailOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));//获取 AbstractQueuedSynchronizer对象 tail字段在内存中的相对偏移量,用于修改内存值
unsafe.compareAndSwapObject(this( AbstractQueuedSynchronizer 对象), tailOffset, expect, update);//如果内存值与 expect值相同,则修改其值为 update新值。
线程安全性在于如果内存值与 expect值相同,则认为没有其它线程修改,则更新并返回真, 否则返回假compareAndSwapObject本身是原子的。所以线程是安全的。
一般常用方法:
public final long getAndSet(long newValue) {
while (true) {//无限循环直至设置成功
long current = get();//获取前值
if (unsafe.compareAndSwapLong(this, valueOffset, current, newValue));//如果当前值与主内存值相等则设为新值。
return current;
}
}
二.线程的挂起与恢复
Unsafe.park(Thread) //阻塞线程
Unsafe.unPark(Thread) //唤醒线程,如果该线程未阻塞,该线程下次调用park方法时,直接返回,不阻塞。
线程池程序执行时,用jstack查看进程状态时,常看到Unsafe.park
/**
* 获取Unsafe对象
*
*/
public class AppUnsafeUtils {
private static final Unsafe _unsafe;
static{
Unsafe temp= null;
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
temp= (Unsafe) field.get(null);
}catch (Exception e){
Throwables.propagate(e);
}
_unsafe = temp;
}
public static final Unsafe getUnsafe() {
return _unsafe;
}
}