JAVA CAS技术运用于多线程(Unsafe)

JAVA CAS技术运用于多线程(Unsafe)_第1张图片

我们来测试如下代码,注意代码的写法:

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秒)

你可能感兴趣的:(java,cas,unsafe)