上一篇从并发模型Master-Worker说起提到了CAS和Unsafe。
这一篇是一次实践,通过模仿(盗版)AtomicInteger来形成线程安全类编写的思想。当然,这只是一次教学,真正项目中,慎用。
先给出编写好的MyAtomicInteger源码,这个就是盗版AtomicInteger的。只有些许变化。
package com.chen.cas;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
* Created by CHEN on 2016/9/28.
*
* 这是一次对AtomicInteger的盗版
*/
public class MyAtomicInteger {
private static final sun.misc.Unsafe UNSAFE;
private static final long valueOffset;
private volatile int value;//可视的值
static {
try {
//请看这个方法解释
UNSAFE = MyAtomicInteger.getUnsafe();//sun.misc.Unsafe.getUnsafe();
Class<?> k = MyAtomicInteger.class;//当前类
valueOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("value"));//对应可视的值
} catch (Exception e) {
throw new Error(e);
}
}
/**
* 初始化
* @param initalValue
*/
public MyAtomicInteger(int initalValue) {
this.value = initalValue;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
//传入增长的幅度
public final int addAndGet(int delta) {
//调用Unsafe的native方法
return UNSAFE.getAndAddInt(this,valueOffset,delta);
}
/**
* 这个方法是和AtomicInteger唯一的区别
* sun.misc.Unsafe这个类是如此地不安全,
* 以至于JDK开发者增加了很多特殊限制来访问它。
* 它的构造器是私有的,
* 工厂方法getUnsafe()的调用器只能被Bootloader加载。
* 如你在下面代码片段的第8行所见,
* 这个家伙甚至没有被任何类加载器加载,
* 所以它的类加载器是null。
* 它会抛出SecurityException 异常来阻止侵入者。
*
* 因此 我们只能通过反射来获得。
* @return
*/
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe)f.get(null);
} catch (Exception e) {
return null;
}
}
//重写toString
public String toString() {
return Integer.toString(getValue());
}
}
测试类
package com.chen.cas;
/**
* Created by CHEN on 2016/9/28.
*/
public class Application {
public volatile static MyAtomicInteger NUM = new MyAtomicInteger(0);
//public volatile static AtomicInteger NUM = new AtomicInteger(0);
public static void main(String[] args) {
//String s = "";
for (int i = 0; i <= 1000; i++) {
Thread thread=new Thread(() -> {
try {
// synchronized (s) {
Thread.sleep(10);
Application.NUM.addAndGet(1);
System.out.println(Application.NUM);
// }
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
try {
Thread.sleep(1000);//此处不能用join,因为没有命名
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("值为" + Application.NUM);
}
}
以上就是怎么写一个线程安全共享对象的例子。以此类推,也可以写成更多的方法。Unsafe下提供了很多的native方法,都是靠底层代码,信号量进行隔离操作。