java多线程学习(七) 之 atomic操作

有些时候,我们希望对一个数值类型的操作是一个原子操作,比如一个计数器,我们希望对一个计数器++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 保证对一个对象的成员的操作的原子性

  1. 阿塔历斯说道:

    java,唯一一个自学的语言

留言

提示:你的email不会被公布,欢迎留言^_^

*

验证码 *