咱们来测试以下代码,注意代码的写法:java
一、普通的写法:测试
if (unsafe_var == 23) {this
// System.out.println("我判断出来了,unsafe_var ==23,我设置为46..");.net
// try {线程
// //模拟业务代码rest
// Thread.sleep(1000);code
// } catch (InterruptedException e) {对象
// e.printStackTrace();blog
// }图片
// unsafe_var = 46;
// }
能够看到打印出多行:
我判断出来了,unsafe_var ==23,我设置为46..
我判断出来了,unsafe_var ==23,我设置为46..
二、用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秒)