有些时候,我们希望对一个数值类型的操作是一个原子操作,比如一个计数器,我们希望对一个计数器++i 之后,可以拿到的i是++之后的值。
你如果是这样写 m=++i; 当前i可能是2,再执行++i之后是3,此时如果另外的线程也进行了++操作,那当赋值给m的时候,可能有一定的几率就不是3了。
要保证这样的原子操作,可以使用线程同步的方式来实现,但是使用AtomicInteger,会更方便一些。
例:
1 2 | AtomicInteger atomic = new AtomicInteger(0); int num = atomic.incrementAndGet(); |
incrementAndGet方法保证返回的结果是+1之后的结果。
此外它还有一系列的原子性操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | atomic.getAndDecrement(); //num = i--; atomic.getAndIncrement(); //num = i++; atomic.getAndAdd(3); //num = i; i+=3; atomic.getAndSet(3); //num = i; i=3; atomic.decrementAndGet(); //num = --i; atomic.incrementAndGet(); //num = ++i; atomic.addAndGet(3); //i+=3; num = i; //atomic.set(3); //i=3; atomic.compareAndSet(2, 3); //if(i==2) i=3; |
这些操作,保证了对一个数值对象,进行基本操作的原子性。保证了一个线程在对一个数值进行操作之后,拿到得是自己操作后的结果,而不是别的线程操作后的结果。
在实际中使用到的场景主要是多线程下的计数器,版本号等,虽然和Lock实现(ReentrantLock)的原理都一样,都是使用了UnSafe类native的compareAndSwapInt等方法实现的,但是至少在用法上更简洁,更方便。
除了AtomicInteger之外,还有AtomicBoolean,AtomicLong。都是保证对数值类型的操作的原子性。
AtomicReference 是对一个对象引用的原子操作。
举例:
1 2 3 4 5 6 7 8 9 10 | MyObject p1 = new MyObject(1); AtomicReference<MyObject> pR = new AtomicReference<MyObject>(p1); pR.compareAndSet(p1, new MyObject(2)); 相当于: MyObject p1 = new MyObject(1); MyObject pR = p1; if(pR == p1) { pR = new MyObject(2); } |
保证对一个对象引用的原子操作。
此外还有他们的衍生类型
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray 保证对数组类型里的元素的操作的原子性。
AtomicIntegerFieldUpdater/AtomicLongFieldUpdater/AtomicReferenceFieldUpdater 保证对一个对象的成员的操作的原子性
除非注明,赵岩的博客文章均为原创,转载请以链接形式标明本文地址
本文地址:https://zhaoyanblog.com/archives/267.html
java,唯一一个自学的语言