我们来测试如下代码,注意代码的写法:
1、普通的写法:
if (unsafe_var == 23) {
// System.out.println(“我判断出来了,unsafe_var ==23,我设置为46..“);
// try {
// //模拟业务代码
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// unsafe_var = 46;
// }
可以看到打印出多行:
我判断出来了,unsafe_var ==23,我设置为46..
我判断出来了,unsafe_var ==23,我设置为46..
2、用Unsafe提供的CAS技术,可以这样写:
if (unsafe.compareAndSwapInt(this, intParamOffset, 23, 46)) {
try {
////模拟业务代码
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我判断出来了,unsafe_var == 23,我设置为46..");
}
由于原子性,多个线程只会打印一行:
我判断出来了,unsafe_var == 23,我设置为46.
测试代码如下:
package com.xue.gang.volatiler.unsafe;
import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import sun.misc.Unsafe;
public class UnsafeRunner {
public static void main(String args[]) throws InterruptedException {
int size = 1000;
CountDownLatch countDownLatch = new CountDownLatch(size);
TomUnsafeRunner tomRunner = new TomUnsafeRunner(false, countDownLatch,
"runner");
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 1; i <= size; i++) {
executorService.execute(new Thread2RunUnsafe(countDownLatch,
tomRunner, i + "_号"));
}
countDownLatch.await();
executorService.shutdown();
// new Thread(volatileRunner).start();
}
static class Thread2RunUnsafe implements Runnable {
private CountDownLatch countDownLatch;
private TomUnsafeRunner tomRunner;
private String name;
public Thread2RunUnsafe(CountDownLatch countDownLatch,
TomUnsafeRunner tomRunner, String name) {
super();
this.countDownLatch = countDownLatch;
this.tomRunner = tomRunner;
this.name = name;
}
public void run() {
System.out.println(this.name + ":running...");
this.tomRunner.doWork();
System.out.println(this.name + ":结束...");
this.countDownLatch.countDown();
}
}
static class TomUnsafeRunner {
volatile boolean shutdownRequested = false;
// boolean shutdownRequested = false;
String name;
int unsafe_var = 23;
public TomUnsafeRunner(boolean shutdownRequested,
CountDownLatch countDownLatch, String name) {
super();
this.shutdownRequested = shutdownRequested;
this.name = name;
}
public void shutdown() {
this.shutdownRequested = true;
}
public void doWork() {
////////////////////一般写法///////////////
// if (unsafe_var == 23) {
// System.out.println(“我判断出来了,unsafe_var ==23,我设置为46..“);
// try {
// //模拟业务代码
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// unsafe_var = 46;
// }
/////////////////用JAVA CAS技术
Unsafe unsafe = UnsafeSupport.getInstance();
Class clazz = TomUnsafeRunner.class;
Field[] fields = clazz.getDeclaredFields();
System.out.println("fieldName:fieldOffset");
// 获取属性偏移量,可以通过这个偏移量给属性设置
for (Field f : fields) {
System.out.println(f.getName() + ":"
+ unsafe.objectFieldOffset(f));
}
// arg0, arg1, arg2, arg3 分别是目标对象实例,目标对象属性偏移量,当前预期值,要设的值
// unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)
// 偏移量编译后一般不会变的,intParam这个属性的偏移量
// unsafe_var:8
long intParamOffset = 8;
if (unsafe.compareAndSwapInt(this, intParamOffset, 23, 46)) {
try {
////模拟业务代码
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我判断出来了,unsafe_var == 23,我设置为46..");
}
}
}
static class UnsafeSupport {
//private static Logger log = Logger.getLogger(UnsafeSupport.class);
private static Unsafe unsafe;
static {
Field field;
try {
// 由反编译Unsafe类获得的信息
field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
// 获取静态属性,Unsafe在启动JVM时随rt.jar装载
unsafe = (Unsafe) field.get(null);
} catch (Exception e) {
//log.error("Get Unsafe instance occur error", e);
}
}
/**
* 获取{@link Unsafe }
*/
public static Unsafe getInstance() {
return unsafe;
}
}
}
运行以上代码,设置Eclipse:
将Windows->Preferences->Java-Complicer->Errors/Warnings->Deprecated and restricted API,中的Forbidden references(access rules)设置为Warning,即可以编译通过。
参考blog:
http://zeige.iteye.com/blog/1182571
http://blog.csdn.net/hengyunabc/article/details/7657934
(作者有个测试,unsafe写入1百万条log用时0.234秒,用java自带的logger,用时7.347秒)