JAVA CAS技術運用於多線程(Unsafe)

在此輸入圖片描述

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

相關文章
相關標籤/搜索