读书人

原子计量器种AtomicLong, AtomicInteg

发布时间: 2012-12-24 10:43:14 作者: rapoo

原子计量器类AtomicLong, AtomicInteger, AtomicReference

J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增、减、赋值(更新)操作. 比如对于++运算符AtomicInteger可以将它持有的integer 能够atomic 地递增。在需要访问两个或两个以上 atomic变量的程序代码(或者是对单一的atomic变量执行两个或两个以上的操作)通常都需要被synchronize以便两者的操作能够被当作是一个atomic的单元。

对array atomic变量来说,一次只有一个索引变量可以变动,并没有功能可以对整个array做atomic化的变动。

关于Atomic的几个方法
getAndSet() : 设置新值,返回旧值.
compareAndSet(expectedValue, newValue) : 如果当前值(current value)等于期待的值(expectedValue), 则原子地更新指定值为新值(newValue), 如果更新成功,返回true, 否则返回false, 换句话可以这样说: 将原子变量设置为新的值, 但是如果从我上次看到的这个变量之后到现在被其他线程修改了(和我期望看到的值不符), 那么更新失败

从effective java (2)中拿来的一个关于AtomicReference的一个例子:
Java代码

Java代码
    public?class?AtomicTest?{??? ?? ????private?int?x,?y;??? ?? ?? ?? ????private?enum?State?{??? ?? ????????NEW,?INITIALIZING,?INITIALIZED??? ?? ????};??? ?? ?? ?? ????private?final?AtomicReference<State>?init?=?new?AtomicReference<State>(State.NEW);??? ?? ??????? ?? ????public?AtomicTest()?{??? ?? ????}??? ?? ??????? ?? ????public?AtomicTest(int?x,?int?y)?{??? ?? ????????initialize(x,?y);??? ?? ????}??? ?? ?? ?? ????private?void?initialize(int?x,?int?y)?{??? ?? ????????if?(!init.compareAndSet(State.NEW,?State.INITIALIZING))?{??? ?? ????????????throw?new?IllegalStateException("initialize?is?error");??? ?? ????????}??? ?? ????????this.x?=?x;??? ?? ????????this.y?=?y;??? ?? ????????init.set(State.INITIALIZED);??? ?? ????}??? ?? ?? ?? ????public?int?getX()?{??? ?? ????????checkInit();??? ?? ????????return?x;??? ?? ????}??? ?? ?? ?? ????public?int?getY()?{??? ?? ????????checkInit();??? ?? ????????return?y;??? ?? ????}??? ?? ??????? ?? ????private?void?checkInit()?{??? ?? ????????if?(init.get()?==?State.INITIALIZED)?{??? ?? ????????????throw?new?IllegalStateException("uninitialized");??? ?? ????????}??? ?? ????}??? ?? ??????? ?? }?? ?? ?? public?class?AtomicTest?{ ?? ????private?int?x,?y; ?? ?? ????private?enum?State?{ ?? ????????NEW,?INITIALIZING,?INITIALIZED ?? ????}; ?? ?? ????private?final?AtomicReference<State>?init?=?new?AtomicReference<State>(State.NEW); ?? ???? ?? ????public?AtomicTest()?{ ?? ????} ?? ???? ?? ????public?AtomicTest(int?x,?int?y)?{ ?? ????????initialize(x,?y); ?? ????} ?? ?? ????private?void?initialize(int?x,?int?y)?{ ?? ????????if?(!init.compareAndSet(State.NEW,?State.INITIALIZING))?{ ?? ????????????throw?new?IllegalStateException("initialize?is?error"); ?? ????????} ?? ????????this.x?=?x; ?? ????????this.y?=?y; ?? ????????init.set(State.INITIALIZED); ?? ????} ?? ?? ????public?int?getX()?{ ?? ????????checkInit(); ?? ????????return?x; ?? ????} ?? ?? ????public?int?getY()?{ ?? ????????checkInit(); ?? ????????return?y; ?? ????} ?? ???? ?? ????private?void?checkInit()?{ ?? ????????if?(init.get()?==?State.INITIALIZED)?{ ?? ????????????throw?new?IllegalStateException("uninitialized"); ?? ????????} ?? ????} ?? ???? ?? }??
public class AtomicTest {       private int x, y;         private enum State {           NEW, INITIALIZING, INITIALIZED       };         private final AtomicReference<State> init = new AtomicReference<State>(State.NEW);              public AtomicTest() {       }              public AtomicTest(int x, int y) {           initialize(x, y);       }         private void initialize(int x, int y) {           if (!init.compareAndSet(State.NEW, State.INITIALIZING)) {               throw new IllegalStateException("initialize is error");           }           this.x = x;           this.y = y;           init.set(State.INITIALIZED);       }         public int getX() {           checkInit();           return x;       }         public int getY() {           checkInit();           return y;       }              private void checkInit() {           if (init.get() == State.INITIALIZED) {               throw new IllegalStateException("uninitialized");           }       }          }  public class AtomicTest { private int x, y; private enum State {  NEW, INITIALIZING, INITIALIZED }; private final AtomicReference<State> init = new AtomicReference<State>(State.NEW);  public AtomicTest() { }  public AtomicTest(int x, int y) {  initialize(x, y); } private void initialize(int x, int y) {  if (!init.compareAndSet(State.NEW, State.INITIALIZING)) {   throw new IllegalStateException("initialize is error");  }  this.x = x;  this.y = y;  init.set(State.INITIALIZED); } public int getX() {  checkInit();  return x; } public int getY() {  checkInit();  return y; }  private void checkInit() {  if (init.get() == State.INITIALIZED) {   throw new IllegalStateException("uninitialized");  } } }



上面的例子比较容易懂, 不过貌似没什么价值, 而在实际的应用中, 我们一般采用下面的方式来使用atomic class:
Java代码

Java代码
    public?class?CounterTest?{??? ?? ????AtomicInteger?counter?=?new?AtomicInteger(0);??? ?? ?? ?? ????public?int?count()?{??? ?? ????????int?result;??? ?? ????????boolean?flag;??? ?? ????????do?{??? ?? ????????????result?=?counter.get();??? ?? ????????????//?断点??? ?? ????????????//?单线程下,?compareAndSet返回永远为true,??? ?? ????????????//?多线程下,?在与result进行compare时,?counter可能被其他线程set了新值,?这时需要重新再取一遍再比较,??? ?? ????????????//?如果还是没有拿到最新的值,?则一直循环下去,?直到拿到最新的那个值??? ?? ????????????flag?=?counter.compareAndSet(result,?result?+?1);??? ?? ????????}?while?(!flag);??? ?? ?? ?? ????????return?result;??? ?? ????}??? ?? ?? ?? ????public?static?void?main(String[]?args)?{??? ?? ????????final?CounterTest?c?=?new?CounterTest();??? ?? ????????new?Thread()?{??? ?? ????????????@Override?? ?? ????????????public?void?run()?{??? ?? ????????????????c.count();??? ?? ????????????}??? ?? ????????}.start();??? ?? ?? ?? ????????new?Thread()?{??? ?? ????????????@Override?? ?? ????????????public?void?run()?{??? ?? ????????????????c.count();??? ?? ????????????}??? ?? ????????}.start();??? ?? ?? ?? ????????new?Thread()?{??? ?? ????????????@Override?? ?? ????????????public?void?run()?{??? ?? ????????????????c.count();??? ?? ????????????}??? ?? ????????}.start();??? ?? ????}??? ?? }?? ?? ?? public?class?CounterTest?{ ?? ????AtomicInteger?counter?=?new?AtomicInteger(0); ?? ?? ????public?int?count()?{ ?? ????????int?result; ?? ????????boolean?flag; ?? ????????do?{ ?? ????????????result?=?counter.get(); ?? ????????????//?断点 ?? ????????????//?单线程下,?compareAndSet返回永远为true, ?? ????????????//?多线程下,?在与result进行compare时,?counter可能被其他线程set了新值,?这时需要重新再取一遍再比较, ?? ????????????//?如果还是没有拿到最新的值,?则一直循环下去,?直到拿到最新的那个值 ?? ????????????flag?=?counter.compareAndSet(result,?result?+?1); ?? ????????}?while?(!flag); ?? ?? ????????return?result; ?? ????} ?? ?? ????public?static?void?main(String[]?args)?{ ?? ????????final?CounterTest?c?=?new?CounterTest(); ?? ????????new?Thread()?{ ?? ????????????@Override?? ????????????public?void?run()?{ ?? ????????????????c.count(); ?? ????????????} ?? ????????}.start(); ?? ?? ????????new?Thread()?{ ?? ????????????@Override?? ????????????public?void?run()?{ ?? ????????????????c.count(); ?? ????????????} ?? ????????}.start(); ?? ?? ????????new?Thread()?{ ?? ????????????@Override?? ????????????public?void?run()?{ ?? ????????????????c.count(); ?? ????????????} ?? ????????}.start(); ?? ????} ?? }??
public class CounterTest {       AtomicInteger counter = new AtomicInteger(0);         public int count() {           int result;           boolean flag;           do {               result = counter.get();               // 断点               // 单线程下, compareAndSet返回永远为true,               // 多线程下, 在与result进行compare时, counter可能被其他线程set了新值, 这时需要重新再取一遍再比较,               // 如果还是没有拿到最新的值, 则一直循环下去, 直到拿到最新的那个值               flag = counter.compareAndSet(result, result + 1);           } while (!flag);             return result;       }         public static void main(String[] args) {           final CounterTest c = new CounterTest();           new Thread() {               @Override              public void run() {                   c.count();               }           }.start();             new Thread() {               @Override              public void run() {                   c.count();               }           }.start();             new Thread() {               @Override              public void run() {                   c.count();               }           }.start();       }   }  public class CounterTest { AtomicInteger counter = new AtomicInteger(0); public int count() {  int result;  boolean flag;  do {   result = counter.get();   // 断点   // 单线程下, compareAndSet返回永远为true,   // 多线程下, 在与result进行compare时, counter可能被其他线程set了新值, 这时需要重新再取一遍再比较,   // 如果还是没有拿到最新的值, 则一直循环下去, 直到拿到最新的那个值   flag = counter.compareAndSet(result, result + 1);  } while (!flag);  return result; } public static void main(String[] args) {  final CounterTest c = new CounterTest();  new Thread() {   @Override   public void run() {    c.count();   }  }.start();  new Thread() {   @Override   public void run() {    c.count();   }  }.start();  new Thread() {   @Override   public void run() {    c.count();   }  }.start(); }}


类似i++这样的"读-改-写"复合操作(在一个操作序列中, 后一个操作依赖前一次操作的结果), 在多线程并发处理的时候会出现问题, 因为可能一个线程修改了变量, 而另一个线程没有察觉到这样变化, 当使用原子变量之后, 则将一系列的复合操作合并为一个原子操作,从而避免这种问题, i++=>i.incrementAndGet()
原子变量只能保证对一个变量的操作是原子的, 如果有多个原子变量之间存在依赖的复合操作, 也不可能是安全的, 另外一种情况是要将更多的复合操作作为一个原子操作, 则需要使用synchronized将要作为原子操作的语句包围起来. 因为涉及到可变的共享变量(类实例成员变量)才会涉及到同步, 否则不必使用synchronized

1 楼 543089122 2011-09-29 LZ这代码贴的。。。惨不忍睹

读书人网 >编程

热点推荐