多线程安全和高效之无锁机制(CAS)和unsafe类

unsafe类给我们提供了很多很牛逼方法,他的操作都是原子性的,用来获取内存地址处的值并修修改,它的修改逻辑是对比内存里地址处的值是否和预期值一样(没有多线程修并发修改的情况下是一样的),如果不一样,说明该值被修改了,返回false,否则返回true,它是Java版本的乐观锁。Java中很多地方都会用到这个方法。如果别人问你ABA的问题,你就告诉他,Java CAS算法不认为ABA是个问题。

 

首先来看下我们的原子类AtomicInteger类中的incrementAndGet()方法,意思是一个指令完成原来++操作两个指令才能完成的操作,所以成为称为原子操作,

 

public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

 

public final int getAndAddInt(Object arg0, long arg1, int arg3) {
int arg4;
do {
arg4 = this.getIntVolatile(arg0, arg1);
} while (!this.compareAndSwapInt(arg0, arg1, arg4, arg4 + arg3));

return arg4;
}

public final native boolean compareAndSwapInt(Object arg0, long arg1, int arg3, int arg4);

 这个方法是关键,称为比较和替换,第一个参数是是要修改的对象,第二个参数是相对对象的内存偏移地址,第三个参数是程序员预期的值,就是当前值,第四个参数是程序员想改成的值。

类似的方法有compareAndSwapLong;compareAndSwapObject

废话不多说,直接看怎么使用,怎么获取对象在内存的地址

//获取对象的属性,FieldName是属性名,

Field field = obj.getClass().getDeclaredField(FieldName);

//获取对象属性在内存中相对对象的偏移地址
long sexOffset = unsafe.objectFieldOffset(field);

接下来我们看看怎么去使用它,我直接给出我写的一个简单例子

package com.dome.util;
import java.lang.reflect.Field;
import com.entity.User;
import sun.misc.Unsafe;
@SuppressWarnings("restriction")
public class UnSafeUtil {
public static Unsafe unsafe=null;
static{
unsafe=UnSafeUtil.getInstance();
}
public static Unsafe getInstance(){
Field f = null;
sun.misc.Unsafe unsafe = null;
try {
//theUnsafe是unsafe 内部一个属性名
f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
// 得到Unsafe类的实例
unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return unsafe;
}

public static boolean update(Object obj,String FieldName,Object old,Object news) {
Unsafe unsafe =UnSafeUtil.unsafe;
Field field;
try {
field = obj.getClass().getDeclaredField(FieldName);
long sexOffset = unsafe.objectFieldOffset(field);
if (old instanceof Integer) {
int aa=(Integer)old;
int bb=(Integer)news;


if(unsafe.compareAndSwapInt(obj, sexOffset, aa, bb)) {
System.out.println("更改成功!");
return true;

} else {
System.out.println("更改失败!");
return false;
}
}
if (old instanceof Long) {
long cc=(Long)old;
long dd=(Long)news;


if(unsafe.compareAndSwapLong(obj, sexOffset, cc, dd)) {
System.out.println("更改成功!");
return true;
} else {
System.out.println("更改失败!");
return false;
}
}


if (old instanceof String) {
if(unsafe.compareAndSwapObject(obj, sexOffset, old, news)) {
System.out.println("更改成功!");
return true;
} else {
System.out.println("更改失败!");
return false;
}
}


} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}

public static void main(String[] args) {
   User user=new User();
user.setHight(175);

//hight是User类的一个属性名,将175改成10
UnSafeUtil.update(user, "hight", 175, 10);
//查看修改后的值
System.out.println(user.getHight());

}

}

平时可以直接使用这个工具类直接在多线程下修改数据,无需再对对象加锁了.

unsafe 类还有很多方法很多方法方法,我将这个类的代码贴出来:

package sun.misc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

public final class Unsafe {
private static final Unsafe theUnsafe;
public static final int INVALID_FIELD_OFFSET = -1;
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;
public static final int ARRAY_INT_BASE_OFFSET;
public static final int ARRAY_LONG_BASE_OFFSET;
public static final int ARRAY_FLOAT_BASE_OFFSET;
public static final int ARRAY_DOUBLE_BASE_OFFSET;
public static final int ARRAY_OBJECT_BASE_OFFSET;
public static final int ARRAY_BOOLEAN_INDEX_SCALE;
public static final int ARRAY_BYTE_INDEX_SCALE;
public static final int ARRAY_SHORT_INDEX_SCALE;
public static final int ARRAY_CHAR_INDEX_SCALE;
public static final int ARRAY_INT_INDEX_SCALE;
public static final int ARRAY_LONG_INDEX_SCALE;
public static final int ARRAY_FLOAT_INDEX_SCALE;
public static final int ARRAY_DOUBLE_INDEX_SCALE;
public static final int ARRAY_OBJECT_INDEX_SCALE;
public static final int ADDRESS_SIZE;

private static native void registerNatives();


@CallerSensitive
public static Unsafe getUnsafe() {
Class arg = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(arg.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}

public native int getInt(Object arg0, long arg1);
public native void putInt(Object arg0, long arg1, int arg3);
public native Object getObject(Object arg0, long arg1);
public native void putObject(Object arg0, long arg1, Object arg3);
public native boolean getBoolean(Object arg0, long arg1);
public native void putBoolean(Object arg0, long arg1, boolean arg3);
public native byte getByte(Object arg0, long arg1);
public native void putByte(Object arg0, long arg1, byte arg3);
public native short getShort(Object arg0, long arg1);
public native void putShort(Object arg0, long arg1, short arg3);
public native char getChar(Object arg0, long arg1);
public native void putChar(Object arg0, long arg1, char arg3);
public native long getLong(Object arg0, long arg1);
public native void putLong(Object arg0, long arg1, long arg3)
public native float getFloat(Object arg0, long arg1);
public native void putFloat(Object arg0, long arg1, float arg3);
public native double getDouble(Object arg0, long arg1)
public native void putDouble(Object arg0, long arg1, double arg3);

@Deprecated
public int getInt(Object arg0, int arg1) {
return this.getInt(arg0, (long) arg1);
}

@Deprecated
public void putInt(Object arg0, int arg1, int arg2) {
this.putInt(arg0, (long) arg1, arg2);
}

@Deprecated
public Object getObject(Object arg0, int arg1) {
return this.getObject(arg0, (long) arg1);
}
@Deprecated
public void putObject(Object arg0, int arg1, Object arg2) {
this.putObject(arg0, (long) arg1, arg2);
}
@Deprecated
public boolean getBoolean(Object arg0, int arg1) {
return this.getBoolean(arg0, (long) arg1);
}

@Deprecated
public void putBoolean(Object arg0, int arg1, boolean arg2) {
this.putBoolean(arg0, (long) arg1, arg2);
}
@Deprecated
public byte getByte(Object arg0, int arg1) {
return this.getByte(arg0, (long) arg1);
}
@Deprecated
public void putByte(Object arg0, int arg1, byte arg2) {
this.putByte(arg0, (long) arg1, arg2);
}
@Deprecated
public short getShort(Object arg0, int arg1) {
return this.getShort(arg0, (long) arg1);
}
@Deprecated
public void putShort(Object arg0, int arg1, short arg2) {
this.putShort(arg0, (long) arg1, arg2);
}
@Deprecated
public char getChar(Object arg0, int arg1) {
return this.getChar(arg0, (long) arg1);
}
@Deprecated
public void putChar(Object arg0, int arg1, char arg2) {
this.putChar(arg0, (long) arg1, arg2);
}
@Deprecated
public long getLong(Object arg0, int arg1) {
return this.getLong(arg0, (long) arg1);
}
@Deprecated
public void putLong(Object arg0, int arg1, long arg2) {
this.putLong(arg0, (long) arg1, arg2);
}
@Deprecated
public float getFloat(Object arg0, int arg1) {
return this.getFloat(arg0, (long) arg1);
}
@Deprecated
public void putFloat(Object arg0, int arg1, float arg2) {
this.putFloat(arg0, (long) arg1, arg2);
}
@Deprecated
public double getDouble(Object arg0, int arg1) {
return this.getDouble(arg0, (long) arg1);
}
@Deprecated
public void putDouble(Object arg0, int arg1, double arg2) {
this.putDouble(arg0, (long) arg1, arg2);
}
public native byte getByte(long arg0);
public native void putByte(long arg0, byte arg2);
public native short getShort(long arg0);
public native void putShort(long arg0, short arg2)
public native char getChar(long arg0);
public native void putChar(long arg0, char arg2);
public native int getInt(long arg0);
public native void putInt(long arg0, int arg2);
public native long getLong(long arg0);
public native void putLong(long arg0, long arg2);
public native float getFloat(long arg0);
public native void putFloat(long arg0, float arg2);
public native double getDouble(long arg0);
public native void putDouble(long arg0, double arg2);
public native long getAddress(long arg0);
public native void putAddress(long arg0, long arg2);
public native long allocateMemory(long arg0);
public native long reallocateMemory(long arg0, long arg2);
public native void setMemory(Object arg0, long arg1, long arg3, byte arg5);
public void setMemory(long arg0, long arg2, byte arg4) {
this.setMemory((Object) null, arg0, arg2, arg4);
}
public native void copyMemory(Object arg0, long arg1, Object arg3, long arg4, long arg6);
public void copyMemory(long arg0, long arg2, long arg4) {
this.copyMemory((Object) null, arg0, (Object) null, arg2, arg4);
}
public native void freeMemory(long arg0);
@Deprecated
public int fieldOffset(Field arg0) {
return Modifier.isStatic(arg0.getModifiers())
? (int) this.staticFieldOffset(arg0)
: (int) this.objectFieldOffset(arg0);
}

@Deprecated
public Object staticFieldBase(Class<?> arg0) {
Field[] arg1 = arg0.getDeclaredFields();

for (int arg2 = 0; arg2 < arg1.length; ++arg2) {
if (Modifier.isStatic(arg1[arg2].getModifiers())) {
return this.staticFieldBase(arg1[arg2]);
}
}

return null;
}

public native long staticFieldOffset(Field arg0);
public native long objectFieldOffset(Field arg0);
public native Object staticFieldBase(Field arg0);
public native boolean shouldBeInitialized(Class<?> arg0);
public native void ensureClassInitialized(Class<?> arg0);
public native int arrayBaseOffset(Class<?> arg0);
public native int arrayIndexScale(Class<?> arg0);
public native int addressSize();
public native int pageSize();
public native Class<?> defineClass(String arg0, byte[] arg1, int arg2, int arg3, ClassLoader arg4,
ProtectionDomain arg5);
public native Class<?> defineAnonymousClass(Class<?> arg0, byte[] arg1, Object[] arg2);
public native Object allocateInstance(Class<?> arg0) throws InstantiationException;
@Deprecated
public native void monitorEnter(Object arg0);
@Deprecated
public native void monitorExit(Object arg0);
@Deprecated
public native boolean tryMonitorEnter(Object arg0);
public native void throwException(Throwable arg0);
public final native boolean compareAndSwapObject(Object arg0, long arg1, Object arg3, Object arg4);
public final native boolean compareAndSwapInt(Object arg0, long arg1, int arg3, int arg4);
public final native boolean compareAndSwapLong(Object arg0, long arg1, long arg3, long arg5);
public native Object getObjectVolatile(Object arg0, long arg1);
public native void putObjectVolatile(Object arg0, long arg1, Object arg3);
public native int getIntVolatile(Object arg0, long arg1);
public native void putIntVolatile(Object arg0, long arg1, int arg3);
public native boolean getBooleanVolatile(Object arg0, long arg1);
public native void putBooleanVolatile(Object arg0, long arg1, boolean arg3);
public native byte getByteVolatile(Object arg0, long arg1);
public native void putByteVolatile(Object arg0, long arg1, byte arg3);
public native short getShortVolatile(Object arg0, long arg1);
public native void putShortVolatile(Object arg0, long arg1, short arg3);
public native char getCharVolatile(Object arg0, long arg1);
public native void putCharVolatile(Object arg0, long arg1, char arg3);
public native long getLongVolatile(Object arg0, long arg1);
public native void putLongVolatile(Object arg0, long arg1, long arg3);
public native float getFloatVolatile(Object arg0, long arg1);
public native void putFloatVolatile(Object arg0, long arg1, float arg3);
public native double getDoubleVolatile(Object arg0, long arg1)
public native void putDoubleVolatile(Object arg0, long arg1, double arg3);
public native void putOrderedObject(Object arg0, long arg1, Object arg3);
public native void putOrderedInt(Object arg0, long arg1, int arg3);
public native void putOrderedLong(Object arg0, long arg1, long arg3);
public native void unpark(Object arg0);
public native void park(boolean arg0, long arg1);
public native int getLoadAverage(double[] arg0, int arg1);
public final int getAndAddInt(Object arg0, long arg1, int arg3) {
int arg4;
do {
arg4 = this.getIntVolatile(arg0, arg1);
} while (!this.compareAndSwapInt(arg0, arg1, arg4, arg4 + arg3));


return arg4;
}


public final long getAndAddLong(Object arg0, long arg1, long arg3) {
long arg5;
do {
arg5 = this.getLongVolatile(arg0, arg1);
} while (!this.compareAndSwapLong(arg0, arg1, arg5, arg5 + arg3));


return arg5;
}


public final int getAndSetInt(Object arg0, long arg1, int arg3) {
int arg4;
do {
arg4 = this.getIntVolatile(arg0, arg1);
} while (!this.compareAndSwapInt(arg0, arg1, arg4, arg3));


return arg4;
}


public final long getAndSetLong(Object arg0, long arg1, long arg3) {
long arg5;
do {
arg5 = this.getLongVolatile(arg0, arg1);
} while (!this.compareAndSwapLong(arg0, arg1, arg5, arg3));


return arg5;
}


public final Object getAndSetObject(Object arg0, long arg1, Object arg3) {
Object arg4;
do {
arg4 = this.getObjectVolatile(arg0, arg1);
} while (!this.compareAndSwapObject(arg0, arg1, arg4, arg3));


return arg4;
}


public native void loadFence();


public native void storeFence();


public native void fullFence();


private static void throwIllegalAccessError() {
throw new IllegalAccessError();
}


static {
registerNatives();
Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
theUnsafe = new Unsafe();
ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
ADDRESS_SIZE = theUnsafe.addressSize();
}
}

 

这个类有个这样的方法,是给Java自带的类获取这个Unsafe 实例提供的,外面的类调这个类会报错,

@CallerSensitive
public static Unsafe getUnsafe() {
Class arg = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(arg.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}

 

虽然这个类我们不能new,但是这个类里面有个 private static final Unsafe theUnsafe;属性,我们正是利用这点用反射获取这个Unsafe 的这个属性。

 

道高一尺魔高一丈,这么好用的东西既然不给我们使用.....

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值