1具壮、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray,
AtomicReference等原子類的類,主要用于在高并發(fā)環(huán)境下的高效程序處理,來幫助我們簡化同步處理.
在Java語言中,++i和i++操作并不是線程安全的弦赖,在使用的時(shí)候,不可避免的會(huì)用到synchronized關(guān)鍵字浦辨。而AtomicInteger則通過一種線程安全的加減操作接口蹬竖。
2、AtomicInteger的基本方法
- 創(chuàng)建一個(gè)AtomicInteger
System.out.println(atomicInteger.get());
--->輸出 : 123
- 創(chuàng)建一個(gè)不傳值的流酬,默認(rèn)值為0
AtomicInteger atomicInteger = new AtomicInteger();
System.out.println(atomicInteger.get());
---->輸出: 0
- 獲取和賦值
atomicInteger.get(); //獲取當(dāng)前值
atomicInteger.set(999); //設(shè)置當(dāng)前值
atomicInteger.compareAndSet(expectedValue,newValue)
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(0);
System.out.println(atomicInteger.get());
int expectedValue = 123;
int newValue = 234;
Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
System.out.println(b);
System.out.println(atomicInteger);
}
----》輸出結(jié)果為: 0 false 0
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(123);
System.out.println(atomicInteger.get());
int expectedValue = 123;
int newValue = 234;
Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
System.out.println(b);
System.out.println(atomicInteger);
}
-----》輸出結(jié)果為: 123 true 234
由上可知該方法表示币厕,atomicInteger的值與expectedValue相比較,如果不相等芽腾,則返回false,
atomicInteger原有值保持不變旦装;如果兩者相等,則返回true,atomicInteger的值更新為newValue
- getAndAdd()方法與AddAndGet方法
AtomicInteger atomicInteger = new AtomicInteger(123);
System.out.println(atomicInteger.get()); --123
System.out.println(atomicInteger.getAndAdd(10)); --123 獲取當(dāng)前值摊滔,并加10
System.out.println(atomicInteger.get()); --133
System.out.println(atomicInteger.addAndGet(10)); --143 獲取加10后的值阴绢,先加10
System.out.println(atomicInteger.get()); --143
- getAndDecrement()和DecrementAndGet()方法
AtomicInteger atomicInteger = new AtomicInteger(123);
System.out.println(atomicInteger.get()); --123
System.out.println(atomicInteger.getAndDecrement()); --123 獲取當(dāng)前值并自減
System.out.println(atomicInteger.get()); --122
System.out.println(atomicInteger.decrementAndGet()); --121 先自減再獲取減1后的值
System.out.println(atomicInteger.get()); --121
3、使用AtomicInteger艰躺,即使不用同步塊synchronized呻袭,最后的結(jié)果也是100,可用看出AtomicInteger的作用腺兴,用原子方式更新的int值左电。主要用于在高并發(fā)環(huán)境下的高效程序處理。使用非阻塞算法來實(shí)現(xiàn)并發(fā)控制。
public class Counter {
public static AtomicInteger count = new AtomicInteger(0);
public static void inc(){
try{
Thread.sleep(1); //延遲1毫秒
}catch (InterruptedException e){ //catch住中斷異常篓足,防止程序中斷
e.printStackTrace();
}
count.getAndIncrement();//count值自加1
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(100);
for(int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("運(yùn)行結(jié)果:"+Counter.count);
}
}
運(yùn)行結(jié)果: 100
4段誊、使用普通Integer
public class Counter {
public volatile static int count = 0;
public static void inc(){
try{
Thread.sleep(1); //延遲1毫秒
}catch (InterruptedException e){ //catch住中斷異常,防止程序中斷
e.printStackTrace();
}
count++;//count值自加1
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(100);
for(int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("運(yùn)行結(jié)果:"+Counter.count);
}
}
運(yùn)行結(jié)果:98
5纷纫、如果在inc方法前面加個(gè)synchronized也能是線程安全的枕扫;
它用來修飾一個(gè)方法或者一個(gè)代碼塊的時(shí)候,能夠保證在同一時(shí)刻最多只有一個(gè)線程執(zhí)行該段代碼辱魁。
import java.util.concurrent.CountDownLatch;
/**
* created by guanguan on 2017/10/23
**/
public class Counter {
public volatile static Integer count = 0;
public synchronized static void inc(){
try{
Thread.sleep(1); //延遲1毫秒
}catch (InterruptedException e){ //catch住中斷異常烟瞧,防止程序中斷
e.printStackTrace();
}
count++;//count值自加1
}
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(100);
for(int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
latch.countDown();
}
}).start();
}
latch.await();
System.out.println("運(yùn)行結(jié)果:"+Counter.count);
}
}
運(yùn)行結(jié)果:100
synchronized的使用說明:
一、當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對象object中的這個(gè)synchronized(this)同步代碼塊時(shí)染簇,一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行参滴。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。
二锻弓、然而砾赔,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問該object中的非synchronized(this)同步代碼塊青灼。
三暴心、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí)杂拨,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞专普。
四、第三個(gè)例子同樣適用其它同步代碼塊弹沽。也就是說檀夹,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對象鎖策橘。結(jié)果炸渡,其它線程對該object對象所有同步代碼部分的訪問都被暫時(shí)阻塞。
五丽已、以上規(guī)則對其它對象鎖同樣適用.
6蚌堵、從上面的例子中我們可以看出:使用AtomicInteger是非常的安全的.而且因?yàn)锳tomicInteger由硬件提供原子操作指令實(shí)現(xiàn)的。在非激烈競爭的情況下沛婴,開銷更小吼畏,速度更快。
java的關(guān)鍵域有3個(gè)
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value;
這里瘸味, unsafe是java提供的獲得對對象內(nèi)存地址訪問的類宫仗,注釋已經(jīng)清楚的寫出了,它的作用就是在更新操作時(shí)提供“比較并替換”的作用旁仿。實(shí)際上就是AtomicInteger中的一個(gè)工具藕夫。
valueOffset是用來記錄value本身在內(nèi)存的便宜地址的孽糖,這個(gè)記錄,也主要是為了在更新操作在內(nèi)存中找到value的位置毅贮,方便比較办悟。
注意:value是用來存儲(chǔ)整數(shù)的時(shí)間變量,這里被聲明為volatile滩褥,就是為了保證在更新操作時(shí)病蛉,當(dāng)前線程可以拿到value最新的值(并發(fā)環(huán)境下,value可能已經(jīng)被其他線程更新了)瑰煎。
這里铺然,我們以自增的代碼為例,可以看到這個(gè)并發(fā)控制的核心算法:
源碼
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}