更新時(shí)間:2020-11-06 17:44:58 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1589次
原子性操作,即為最小的操作單元,比如i=1,就是一個(gè)原子性操作,這個(gè)過(guò)程只涉及一個(gè)賦值操作。多線(xiàn)程原子性操作依賴(lài)在J.U.C包下的atomic系列的類(lèi)。它主要包括四類(lèi):基本類(lèi)型,數(shù)組類(lèi)型,屬性原子修改器類(lèi)型,引用類(lèi)型。
1.基本類(lèi)型的實(shí)現(xiàn):
package concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicTest {
private static final AtomicInteger at=new AtomicInteger();
private static final ExecutorService es=Executors.newFixedThreadPool(20);
public static void main(String[] args) {
// TODO Auto-generated method stub
long start=System.currentTimeMillis();
for(int i=0;i<1000;i++)
{
Thread t1=new Thread() {
public void run()
{
System.out.println(Thread.currentThread().getName()+"實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:"+at.incrementAndGet());
}
};
es.execute(t1);
}
try
{
Thread.sleep(5000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
System.out.println("計(jì)算過(guò)程的耗時(shí)為:"+(System.currentTimeMillis()-start-5000));
System.out.println("累加1000次,得到結(jié)果"+at);
}
}
運(yùn)行結(jié)果如下:
pool-1-thread-13實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:984
pool-1-thread-8實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:983
pool-1-thread-14實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:982
pool-1-thread-20實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:981
pool-1-thread-10實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:980
pool-1-thread-12實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:979
pool-1-thread-3實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:978
pool-1-thread-7實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:977
pool-1-thread-4實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:976
pool-1-thread-18實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:1000
pool-1-thread-9實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:999
pool-1-thread-17實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:998
pool-1-thread-6實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:997
pool-1-thread-5實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:996
pool-1-thread-2實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:995
計(jì)算過(guò)程的耗時(shí)為:9
累加1000次,得到結(jié)果1000
由上面可知使用基本類(lèi)型的原子操作類(lèi)進(jìn)行數(shù)字的自增,不僅可以保證操作操作的原子性,而且相對(duì)來(lái)說(shuō)花費(fèi)的時(shí)間代價(jià)比使用synchronized加鎖的時(shí)間代價(jià)要小。
2.數(shù)組類(lèi)型
以下以AtomicIntegerArray為例通過(guò)對(duì)一個(gè)數(shù)組內(nèi)的每個(gè)元素進(jìn)行自增計(jì)算,從而來(lái)介紹數(shù)組類(lèi)型的原子類(lèi)的運(yùn)用。
package concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicTest {
private static final AtomicIntegerArray at=new AtomicIntegerArray(new int[5]);
private static final ExecutorService es=Executors.newFixedThreadPool(20);
public static void main(String[] args) {
// TODO Auto-generated method stub
long start=System.currentTimeMillis();
for(int i=0;i<1000;i++)
{
Thread t1=new Thread() {
public void run()
{
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+"實(shí)現(xiàn)了對(duì)第"+(i+1)+"個(gè)元素一次自增原子操作,結(jié)果為:"+at.incrementAndGet(i));
}
};
es.execute(t1);
}
try
{
Thread.sleep(5000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
System.out.println("計(jì)算過(guò)程的耗時(shí)為:"+(System.currentTimeMillis()-start-5000));
for(int i=0;i<5;i++)
System.out.println("第"+(i+1)+"個(gè)元素累加1000次,得到結(jié)果"+at.get(i));
}
}
運(yùn)行程序結(jié)果如下,其中運(yùn)算過(guò)程部分給出:
pool-1-thread-3實(shí)現(xiàn)了對(duì)第5個(gè)元素一次自增原子操作,結(jié)果為:980
pool-1-thread-20實(shí)現(xiàn)了對(duì)第1個(gè)元素一次自增原子操作,結(jié)果為:989
pool-1-thread-20實(shí)現(xiàn)了對(duì)第2個(gè)元素一次自增原子操作,結(jié)果為:1000
pool-1-thread-20實(shí)現(xiàn)了對(duì)第3個(gè)元素一次自增原子操作,結(jié)果為:1000
pool-1-thread-20實(shí)現(xiàn)了對(duì)第4個(gè)元素一次自增原子操作,結(jié)果為:1000
pool-1-thread-20實(shí)現(xiàn)了對(duì)第5個(gè)元素一次自增原子操作,結(jié)果為:1000
pool-1-thread-15實(shí)現(xiàn)了對(duì)第5個(gè)元素一次自增原子操作,結(jié)果為:998
計(jì)算過(guò)程的耗時(shí)為:9
第1個(gè)元素累加1000次,得到結(jié)果1000
第2個(gè)元素累加1000次,得到結(jié)果1000
第3個(gè)元素累加1000次,得到結(jié)果1000
第4個(gè)元素累加1000次,得到結(jié)果1000
第5個(gè)元素累加1000次,得到結(jié)果1000
從結(jié)果可以看出,數(shù)組類(lèi)型的原子類(lèi)的使用,可以保證每個(gè)元素的自增等操作都滿(mǎn)足原子性。
3.屬性原子修改器
以AtomicIntegerFieldUpdater類(lèi)為例,該類(lèi)有一個(gè)靜態(tài)方法newUpdater(Class tclass,String fieldName),則這個(gè)表示為tclass類(lèi)的fieldName屬性創(chuàng)建一個(gè)屬性原子修改器,如果需要修改該屬性,則只需要調(diào)用原子修改器的方法,比如addAndGet(tclass obj,int delta):該方法表示將該修改器對(duì)應(yīng)的屬性增加delta。以下通過(guò)代碼來(lái)了解屬性原子修改器的作用。
package concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
class Count{
public volatile int number;
}
public class AtomicTest {
private static final AtomicIntegerFieldUpdater
private static final ExecutorService es=Executors.newFixedThreadPool(20);
public static void main(String[] args) {
// TODO Auto-generated method stub
final Count count=new Count();
long start=System.currentTimeMillis();
for(int i=0;i<1000;i++)
{
Thread t1=new Thread() {
public void run()
{
System.out.println(Thread.currentThread().getName()+"實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:"+aifu.addAndGet(count, 1));
}
};
es.execute(t1);
}
try
{
Thread.sleep(5000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
System.out.println("計(jì)算過(guò)程的耗時(shí)為:"+(System.currentTimeMillis()-start-5000));
for(int i=0;i<5;i++)
System.out.println("第"+(i+1)+"個(gè)元素累加1000次,得到結(jié)果"+count.number);
}
}
運(yùn)行以上程序,得到如下結(jié)果:
pool-1-thread-17實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:993
pool-1-thread-5實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:992
pool-1-thread-19實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:991
pool-1-thread-3實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:990
pool-1-thread-15實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:989
pool-1-thread-20實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:988
pool-1-thread-18實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:987
pool-1-thread-6實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:986
pool-1-thread-7實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:985
pool-1-thread-9實(shí)現(xiàn)了一次自增原子操作,結(jié)果為:984
計(jì)算過(guò)程的耗時(shí)為:10
第1個(gè)元素累加1000次,得到結(jié)果1000
第2個(gè)元素累加1000次,得到結(jié)果1000
第3個(gè)元素累加1000次,得到結(jié)果1000
第4個(gè)元素累加1000次,得到結(jié)果1000
第5個(gè)元素累加1000次,得到結(jié)果1000
從上面結(jié)果可以看出,屬性原子修改器的使用也能達(dá)到原子性操作的目的。
4.引用類(lèi)型
以AtomicReference類(lèi)為例,通過(guò)AtomicReference
package concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
class Count{
public int count;
public Count(int count)
{
this.count=count;
}
public String toString()
{
return "這個(gè)對(duì)象的位置是:"+count;
}
}
public class AtomicTest {
private static final AtomicReference
public static void main(String[] args) {
// TODO Auto-generated method stub
Count count=new Count(1001);
long start=System.currentTimeMillis();
ar.set(count);
System.out.println("你好,"+ar.get());
Count count1=new Count(1002);
ar.compareAndSet(count, count1);//內(nèi)存值與count是一樣的,所以值更新為count1
System.out.println("我發(fā)生了改變:"+ar.get());
Count count2=new Count(1003);
ar.compareAndSet(count, count2);//此時(shí)內(nèi)存智為count1,與count不一致,所以無(wú)法更新,因此內(nèi)存值依然為count1
System.out.println("我發(fā)生了改變:"+ar.get());
}
}
運(yùn)行程序,結(jié)果如下:
你好,這個(gè)對(duì)象的位置是:1001
我發(fā)生了改變:這個(gè)對(duì)象的位置是:1002
我發(fā)生了改變:這個(gè)對(duì)象的位置是:1002
以上就是Java多線(xiàn)程原子性操作的實(shí)現(xiàn),總而言之,就是依賴(lài)atomic系列類(lèi)來(lái)實(shí)現(xiàn)的?;绢?lèi)型的類(lèi)主要包括AtomicInteger、AtomicLong、AtomicBoolean等;數(shù)組類(lèi)型主要包括AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray;屬性原子修改器類(lèi)型主要包括AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater ;引用類(lèi)型主要包括AtomicReference、AtomicStampedRerence、AtomicMarkableReference。對(duì)于這些類(lèi)的具體講解可以參照本站的Java多線(xiàn)程教程加以學(xué)習(xí)。
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話(huà)與您溝通安排學(xué)習(xí)