问题:
1 如何构造,经常使用哪些api?
2 怎么实现的原子操作?
3 示例demo
static { try {//1 使用反射获得成员变量"value" // 2 得到"value"在内存中的偏移量, 直接操作内存空间,实现对字段value的操作 valueOffset = unsafe.objectFieldOffset (AtomicBoolean.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); }}/*实现AtomicBoolean两个条件:1 一旦更新,所有的线程读取最新的值2 多线程同步更新 */private volatile int value; //3 volatile使其他线程可见(满足第一个条件)public AtomicBoolean(boolean initialValue) { value = initialValue ? 1 : 0; //4 value的值,要么是1(true),要么是0(false)}public AtomicBoolean() { // 默认是false}public final boolean compareAndSet(boolean expect, boolean update) { //5 把比较和赋值 一起组合也为原子操作,返回boolean int e = expect ? 1 : 0; int u = update ? 1 : 0; // 6 CAS多线程同步更新。这是个阻塞函数,线程会不断尝试执行,直至成功 return unsafe.compareAndSwapInt(this, valueOffset, e, u);}public final void set(boolean newValue) { value = newValue ? 1 : 0; //}
示例demo:
public class BarWorker implements Runnable { private static AtomicBoolean exists = new AtomicBoolean(false); private String name; public BarWorker(String name) { this.name = name; } public void run() { // 只允许一个线程去执行,其余线程不执行 if (exists.compareAndSet(false, true)) { System.out.println(name + " enter"); try { System.out.println(name + " working"); TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // do nothing } System.out.println(name + " leave"); exists.set(false);//设置为false, 另外一个线程开始执行 } else { System.out.println(name + " give up"); } }}
如果我不使用AtomicBoolean,实现同样的功能,会怎么做?
public class BarWorker2 implements Runnable { private static volatile boolean exists = false;//volatile 使变量可视 private String name; public BarWorker2(String name) { this.name = name; } public void run() { // 只允许一个线程去执行,其余线程不执行 if (exists == false) { // 这几行组合在一起类似CAS synchronized (BarWorker2.class) { if (exists == false) { exists = true; System.out.println(name + " enter"); try { System.out.println(name + " working"); TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // do nothing } System.out.println(name + " leave"); } else { System.out.println(name + " give up --- 1"); } } } else { System.out.println(name + " give up --- 2"); } }}