咱們來測試以下代碼,注意代碼的寫法: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秒)