概述
說到線程拭荤,就不得不先說線程和進(jìn)程的關(guān)系茵臭,這里先簡(jiǎn)單解釋一下,進(jìn)程是系統(tǒng)的執(zhí)行單位舅世,一般一個(gè)應(yīng)用程序即是一個(gè)進(jìn)程旦委,程序啟動(dòng)時(shí)系統(tǒng)默認(rèn)有一個(gè)主線程,即是UI線程雏亚,我們知道不能做耗時(shí)任務(wù)缨硝,否則ANR程序無響應(yīng)。這時(shí)需要借助子線程實(shí)現(xiàn)罢低,即多線程查辩。由于線程是系統(tǒng)CPU的最小單位,用多線程其實(shí)就是為了更好的利用cpu的資源网持。
常見多線程方式
1宜岛、繼承Thread類,重寫run函數(shù)方法:
class xx extends Thread{
public void run(){
Thread.sleep(1000); //線程休眠1000毫秒翎碑,sleep使線程進(jìn)入Block狀態(tài)谬返,并釋放資源
}
}
xx.start(); //啟動(dòng)線程,run函數(shù)運(yùn)行
2日杈、實(shí)現(xiàn)Runnable接口,重寫run函數(shù)方法:
Runnable run =new Runnable() {
@Override
public void run() {
}
}
3佑刷、實(shí)現(xiàn)Callable接口,重寫call函數(shù)方法:
Callable call =new Callable() {
@Override
public Object call() throws Exception {
return null;
}
}
小結(jié):Callable 與 Runnable 對(duì)比。
相同:都是可被其它線程執(zhí)行的任務(wù)叨叙。
不同:
①Callable規(guī)定的方法是call()私恬,而Runnable規(guī)定的方法是run().
②Callable的任務(wù)執(zhí)行后可返回值,而Runnable的任務(wù)是不能返回值的
③call()方法可拋出異常麦萤,而run()方法是不能拋出異常的鹿鳖。
④運(yùn)行Callable任務(wù)可拿到一個(gè)Future對(duì)象,F(xiàn)uture表示異步計(jì)算的結(jié)果壮莹。通過Future對(duì)象可了解任務(wù)執(zhí)行情況,可取消任務(wù)的執(zhí)行翅帜。
4、HandlerThread:
handlerThread = new HandlerThread("MyNewThread");//自定義線程名稱
handlerThread.start();
mOtherHandler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg){
if (msg.what == 0x124){
try {
Log.d("HandlerThread", Thread.currentThread().getName());
Thread.sleep(5000);//模擬耗時(shí)任務(wù)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
HandlerThread的好處是代碼看起來沒前面的版本那么亂命满,相對(duì)簡(jiǎn)潔一點(diǎn)涝滴。還有一個(gè)好處就是通過handlerThread.quit()或者quitSafely()使線程結(jié)束自己的生命周期。
4、AsyncTask:
具體的使用代碼就不貼上來了歼疮,可以去看我的一篇博文杂抽。但值得一說的是,上面說過HandlerThread只開一條線程韩脏,任務(wù)都被阻塞在一個(gè)隊(duì)列中缩麸,那么就會(huì)使阻塞的任務(wù)延遲了,而AsyncTask開啟線程的方法asyncTask.execute()默認(rèn)是也是開啟一個(gè)線程和一個(gè)隊(duì)列的赡矢,不過也可以通過asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0)開啟一個(gè)含有5個(gè)新線程的線程池匙睹,也就是說有個(gè)5個(gè)隊(duì)列了,假如說你執(zhí)行第6個(gè)耗時(shí)任務(wù)時(shí)济竹,除非前面5個(gè)都還沒執(zhí)行完痕檬,否則任務(wù)是不會(huì)阻塞的,這樣就可以大大減少耗時(shí)任務(wù)延遲的可能性送浊,這也是它的優(yōu)點(diǎn)所在梦谜。當(dāng)你想多個(gè)耗時(shí)任務(wù)并發(fā)的執(zhí)行,那你更應(yīng)該選擇AsyncTask袭景。
4唁桩、IntentService:
最后是IntentService,相信很多人也不陌生耸棒,它是Service的子類荒澡,用法跟Service也差不多,就是實(shí)現(xiàn)的方法名字不一樣与殃,耗時(shí)邏輯應(yīng)放在onHandleIntent(Intent intent)的方法體里单山,它同樣有著退出啟動(dòng)它的Activity后不會(huì)被系統(tǒng)殺死的特點(diǎn),而且當(dāng)任務(wù)執(zhí)行完后會(huì)自動(dòng)停止幅疼,無須手動(dòng)去終止它米奸。例如在APP里我們要實(shí)現(xiàn)一個(gè)下載功能,當(dāng)退出頁(yè)面后下載不會(huì)被中斷爽篷,那么這時(shí)候IntentService就是一個(gè)不錯(cuò)的選擇了悴晰。
線程狀態(tài)
1、wait()逐工。使一個(gè)線程處于等待狀態(tài)铡溪,并且釋放所有持有對(duì)象的lock鎖,直到notify()/notifyAll()被喚醒后放到鎖定池(lock blocked pool )泪喊,釋放同步鎖使線程回到可運(yùn)行狀態(tài)(Runnable)棕硫。
2、sleep()窘俺。使一個(gè)線程處于睡眠狀態(tài)饲帅,是一個(gè)靜態(tài)方法复凳,調(diào)用此方法要捕捉Interrupted異常,醒來后進(jìn)入runnable狀態(tài)灶泵,等待JVM調(diào)度育八。
3、notify()赦邻。使一個(gè)等待狀態(tài)的線程喚醒髓棋,注意并不能確切喚醒等待狀態(tài)線程,是由JVM決定且不按優(yōu)先級(jí)惶洲。
4按声、allnotify()。使所有等待狀態(tài)的線程喚醒恬吕,注意并不是給所有線程上鎖签则,而是讓它們競(jìng)爭(zhēng)。
5铐料、join()渐裂。使一個(gè)線程中斷,IO完成會(huì)回到Runnable狀態(tài)钠惩,等待JVM的調(diào)度柒凉。
6、Synchronized()篓跛。使Running狀態(tài)的線程加同步鎖使其進(jìn)入(lock blocked pool ),同步鎖被釋放進(jìn)入可運(yùn)行狀態(tài)(Runnable)膝捞。
注意:當(dāng)線程在runnable狀態(tài)時(shí)是處于被調(diào)度的線程,此時(shí)的調(diào)度順序是不一定的愧沟。Thread類中的yield方法可以讓一個(gè)running狀態(tài)的線程轉(zhuǎn)入runnable蔬咬。
基礎(chǔ)概念
1、 并行央渣。多個(gè)cpu實(shí)例或多臺(tái)機(jī)器同時(shí)執(zhí)行一段代碼计盒,是真正的同時(shí)。
2芽丹、并發(fā)。通過cpu調(diào)度算法卜朗,讓用戶看上去同時(shí)執(zhí)行拔第,實(shí)際上從cpu操作層面不是真正的同時(shí)。
3场钉、線程安全蚊俺。指在并發(fā)的情況之下,該代碼經(jīng)過多線程使用逛万,線程的調(diào)度順序不影響任何結(jié)果泳猬。線程不安全就意味著線程的調(diào)度順序會(huì)影響最終結(jié)果,比如某段代碼不加事務(wù)去并發(fā)訪問。
4得封、線程同步埋心。指的是通過人為的控制和調(diào)度,保證共享資源的多線程訪問成為線程安全忙上,來保證結(jié)果的準(zhǔn)確拷呆。如某段代碼加入@synchronized關(guān)鍵字。線程安全的優(yōu)先級(jí)高于性能優(yōu)化疫粥。
5茬斧、原子性。一個(gè)操作或者一系列操作梗逮,要么全部執(zhí)行要么全部不執(zhí)行项秉。數(shù)據(jù)庫(kù)中的“事物”就是個(gè)典型的院子操作。
6慷彤、可見性娄蔼。當(dāng)一個(gè)線程修改了共享屬性的值,其它線程能立刻看到共享屬性值的更改瞬欧。比如JMM分為主存和工作內(nèi)存贷屎,共享屬性的修改過程是在主存中讀取并復(fù)制到工作內(nèi)存中,在工作內(nèi)存中修改完成之后艘虎,再刷新主存中的值唉侄。若線程A在工作內(nèi)存中修改完成但還來得及刷新主存中的值,這時(shí)線程B訪問該屬性的值仍是舊值野建。這樣可見性就沒法保證属划。
7、有序性候生。程序運(yùn)行時(shí)代碼邏輯的順序在實(shí)際執(zhí)行中不一定有序同眯,為了提高性能,編譯器和處理器都會(huì)對(duì)代碼進(jìn)行重新排序唯鸭。前提是须蜗,重新排序的結(jié)果要和單線程執(zhí)行程序順序一致。
Synchronized 同步
由于java的每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖目溉,當(dāng)用此關(guān)鍵字修飾方法時(shí)明肮, 內(nèi)置鎖會(huì)保護(hù)整個(gè)方法。在調(diào)用該方法前缭付,需要獲得內(nèi)置鎖柿估,否則就處于阻塞狀態(tài)。補(bǔ)充: synchronized關(guān)鍵字也可以修飾靜態(tài)方法陷猫,此時(shí)如果調(diào)用該靜態(tài)方法秫舌,將會(huì)鎖住整個(gè)類的妖。
1、方法同步足陨。給方法增加synchronized修飾符就可以成為同步方法嫂粟,可以是靜態(tài)方法、非靜態(tài)方法钠右,但不能是抽象方法赋元、接口方法。小示例:
public synchronized void aMethod() {
// do something
}
public static synchronized void anotherMethod() {
// do something
}
使用詳解:
線程在執(zhí)行同步方法時(shí)是具有排它性的飒房。當(dāng)任意一個(gè)線程進(jìn)入到一個(gè)對(duì)象的任意一個(gè)同步方法時(shí)搁凸,這個(gè)對(duì)象的所有同步方法都被鎖定了,在此期間狠毯,其他任何線程都不能訪問這個(gè)對(duì)象的任意一個(gè)同步方法护糖,直到這個(gè)線程執(zhí)行完它所調(diào)用的同步方法并從中退出,從而導(dǎo)致它釋放了該對(duì)象的同步鎖之后嚼松。在一個(gè)對(duì)象被某個(gè)線程鎖定之后嫡良,其他線程是可以訪問這個(gè)對(duì)象的所有非同步方法的。
2献酗、塊同步寝受。同步塊是通過鎖定一個(gè)指定的對(duì)象,來對(duì)塊中的代碼進(jìn)行同步罕偎;同步方法和同步塊之間的相互制約只限于同一個(gè)對(duì)象之間很澄,靜態(tài)同步方法只受它所屬類的其它靜態(tài)同步方法的制約,而跟這個(gè)類的實(shí)例沒有關(guān)系颜及。如果一個(gè)對(duì)象既有同步方法甩苛,又有同步塊,那么當(dāng)其中任意一個(gè)同步方法或者同步塊被某個(gè)線程執(zhí)行時(shí)俏站,這個(gè)對(duì)象就被鎖定了讯蒲,其他線程無法在此時(shí)訪問這個(gè)對(duì)象的同步方法,也不能執(zhí)行同步塊肄扎。
3墨林、使用方法同步保護(hù)共享數(shù)據(jù)。示例:
public class ThreadTest implements Runnable{
public synchronized void run(){
for(int i=0;i<10;i++) {
System.out.print(" " + i);
}
}
public static void main(String[] args) {
Runnable r1 = new ThreadTest();
Runnable r2 = new ThreadTest();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}}
示例詳解:
代碼中可見犯祠,run()被加上了synchronized 關(guān)鍵字萌丈,但保護(hù)的并不是共享數(shù)據(jù)。因?yàn)槌绦蛑袃蓚€(gè)線程對(duì)象 t1雷则、t2 其實(shí)是另外兩個(gè)線程對(duì)象 r1、r2 的線程肪笋,這個(gè)聽起來繞月劈,但是一眼你就能看明白度迂;因?yàn)椴煌木€程對(duì)象的數(shù)據(jù)是不同的,即 r1,r2 有各自的run()方法猜揪,所以輸出結(jié)果就無法預(yù)知惭墓。這時(shí)使用 synchronized 關(guān)鍵字可以讓某個(gè)時(shí)刻只有一個(gè)線程可以訪問該對(duì)象synchronized數(shù)據(jù)。每個(gè)對(duì)象都有一個(gè)“鎖標(biāo)志”而姐,當(dāng)這個(gè)對(duì)象的一個(gè)線程訪問這個(gè)對(duì)象的某個(gè)synchronized 數(shù)據(jù)時(shí)腊凶,這個(gè)對(duì)象的所有被synchronized 修飾的數(shù)據(jù)將被上鎖(因?yàn)椤版i標(biāo)志”被當(dāng)前線程拿走了),只有當(dāng)前線程訪問完它要訪問的synchronized 數(shù)據(jù)時(shí)拴念,當(dāng)前線程才會(huì)釋放“鎖標(biāo)志”钧萍,這樣同一個(gè)對(duì)象的其它線程才有機(jī)會(huì)訪問synchronized 數(shù)據(jù)。
接下來政鼠,我們把 r2 給注釋掉风瘦, 即只保留一個(gè) r 對(duì)象。如下:
public class ThreadTest implements Runnable{
public synchronized void run(){
for(int i=0;i<10;i++){
System.out.print(" " + i);
}
}
public static void main(String[] args){
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}}
示例詳解:
如果你運(yùn)行1000 次這個(gè)程序公般,它的輸出結(jié)果也一定每次都是:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9万搔。因?yàn)檫@里的synchronized 保護(hù)的是共享數(shù)據(jù)。t1,t2 是同一個(gè)對(duì)象(r)的兩個(gè)線程官帘,當(dāng)其中的一個(gè)線程(例如:t1)開始執(zhí)行run()方法時(shí)瞬雹,由于run()受synchronized保護(hù),所以同一個(gè)對(duì)象的其他線程(t2)無法訪問synchronized 方法(run 方法)刽虹。只有當(dāng)t1執(zhí)行完后t2 才有機(jī)會(huì)執(zhí)行酗捌。
4、使用塊同步状婶,示例:
public class ThreadTest implements Runnable{
public void run(){
synchronized(this){ //與上面示例不同于關(guān)鍵字使用
for(int i=0;i<10;i++){
System.out.print(" " + i);
}
}
}
public static void main(String[] args){
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
示例詳解:
這個(gè)與上面示例的運(yùn)行結(jié)果也一樣的意敛。這里是把保護(hù)范圍縮到最小,this 代表 ‘這個(gè)對(duì)象’ 膛虫。沒有必要把整個(gè)run()保護(hù)起來草姻,run()中的代碼只有一個(gè)for循環(huán),所以只要保護(hù)for 循環(huán)就可以了稍刀。
最后撩独,再看一個(gè)示例:
public class ThreadTest implements Runnable{
public void run(){
for(int k=0;k<5;k++){
System.out.println(Thread.currentThread().getName()+ " : for loop : " + k);
}
synchronized(this){
for(int k=0;k<5;k++) {
System.out.println(Thread.currentThread().getName()+ " : synchronized for loop : " + k);
}} }
public static void main(String[] args){
Runnable r = new ThreadTest();
Thread t1 = new Thread(r,"t1_name");
Thread t2 = new Thread(r,"t2_name");
t1.start();
t2.start();
} }
//運(yùn)行結(jié)果:
t1_name : for loop : 0
t1_name : for loop : 1
t1_name : for loop : 2
t2_name : for loop : 0
t1_name : for loop : 3
t2_name : for loop : 1
t1_name : for loop : 4
t2_name : for loop : 2
t1_name : synchronized for loop : 0
t2_name : for loop : 3
t1_name : synchronized for loop : 1
t2_name : for loop : 4
t1_name : synchronized for loop : 2
t1_name : synchronized for loop : 3
t1_name : synchronized for loop : 4
t2_name : synchronized for loop : 0
t2_name : synchronized for loop : 1
t2_name : synchronized for loop : 2
t2_name : synchronized for loop : 3
t2_name : synchronized for loop : 4
示例詳解:
第一個(gè)for 循環(huán)沒有受synchronized 保護(hù)。對(duì)于第一個(gè)for 循環(huán)账月,t1,t2 可以同時(shí)訪問综膀。運(yùn)行結(jié)果表明t1 執(zhí)行到了k=2 時(shí),t2 開始執(zhí)行了局齿。t1 首先執(zhí)行完了第一個(gè)for 循環(huán)剧劝,此時(shí)t2還沒有執(zhí)行完第一個(gè)for 循環(huán)(t2 剛執(zhí)行到k=2)。t1 開始執(zhí)行第二個(gè)for 循環(huán)抓歼,當(dāng)t1的第二個(gè)for 循環(huán)執(zhí)行到k=1 時(shí)讥此,t2 的第一個(gè)for 循環(huán)執(zhí)行完了拢锹。t2 想開始執(zhí)行第二個(gè)for 循環(huán),但由于t1 首先執(zhí)行了第二個(gè)for 循環(huán)萄喳,這個(gè)對(duì)象的鎖標(biāo)志自然在t1 手中(synchronized 方法的執(zhí)行權(quán)也就落到了t1 手中)卒稳,在t1 沒執(zhí)行完第二個(gè)for 循環(huán)的時(shí)候,它是不會(huì)釋放鎖標(biāo)志的他巨。所以t2 必須等到t1 執(zhí)行完第二個(gè)for 循環(huán)后充坑,它才可以執(zhí)行第二個(gè)for 循環(huán)。
Volatile 同步
a.volatile關(guān)鍵字為域變量的訪問提供了一種免鎖機(jī)制
b.使用volatile修飾域相當(dāng)于告訴虛擬機(jī)該域可能會(huì)被其他線程更新
c.因此每次使用該域就要重新計(jì)算染突,而不是使用寄存器中的值
d.volatile不會(huì)提供任何原子操作捻爷,它也不能用來修飾final類型的變量
例如:
在上面的例子當(dāng)中,只需在account前面加上volatile修飾觉痛,即可實(shí)現(xiàn)線程同步役衡。
代碼實(shí)例:
//只給出要修改的代碼,其余代碼與上同
class Bank {
//需要同步的變量加上volatile
private volatile int account = 100;
public int getAccount() {
return account;
}
//這里不再需要synchronized
public void save(int money) {
account += money;
}
}
注:多線程中的非同步問題主要出現(xiàn)在對(duì)域的讀寫上薪棒,如果讓域自身避免這個(gè)問題手蝎,則就不需要修改操作該域的方法。 用final域俐芯,有鎖保護(hù)的域和volatile域可以避免非同步的問題棵介。
重入鎖同步
在 JavaSE5.0中 新增了一個(gè) java.util.concurrent 包來支持同步。
ReentrantLock類是可重入吧史、互斥邮辽、實(shí)現(xiàn)了Lock接口的鎖,它與使用synchronized方法和快具有相同的基本行為和語義贸营,并且擴(kuò)展了其能力吨述。 ReenreantLock類的常用方法有:
ReentrantLock() : 創(chuàng)建一個(gè)ReentrantLock實(shí)例
lock() : 獲得鎖
unlock() : 釋放鎖
注:ReentrantLock()還有一個(gè)可以創(chuàng)建公平鎖的構(gòu)造方法,但由于能大幅度降低程序運(yùn)行效率钞脂,不推薦使用 例如:
class Bank {
private int account = 100;
//需要聲明這個(gè)鎖
private Lock lock = new ReentrantLock();
public int getAccount() {
return account;
}
//這里不再需要synchronized
public void save(int money) {
lock.lock();
try{
account += money;
}finally{
lock.unlock();
}
}
}
注:關(guān)于Lock對(duì)象和synchronized關(guān)鍵字的選擇:
a.最好兩個(gè)都不用揣云,使用一種java.util.concurrent包提供的機(jī)制,能夠幫助用戶處理所有與鎖相關(guān)的代碼冰啃。
b.如果synchronized關(guān)鍵字能滿足用戶的需求邓夕,就用synchronized,因?yàn)樗芎?jiǎn)化代碼
c.如果需要更高級(jí)的功能阎毅,就用ReentrantLock類焚刚,此時(shí)要注意及時(shí)釋放鎖,否則會(huì)出現(xiàn)死鎖扇调,通常在finally代碼釋放鎖
局部變量同步
如果使用ThreadLocal管理變量矿咕,則每一個(gè)使用該變量的線程都獲得該變量的副本,副本之間相互獨(dú)立,這樣每一個(gè)線程都可以隨意修改自己的變量副本痴腌,而不會(huì)對(duì)其他線程產(chǎn)生影響雌团。 ThreadLocal 類的常用方法:
ThreadLocal() : 創(chuàng)建一個(gè)線程本地變量
get() : 返回此線程局部變量的當(dāng)前線程副本中的值
initialValue() : 返回此線程局部變量的當(dāng)前線程的"初始值"
set(T value) : 將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為value
例如:
public class Bank{
//使用ThreadLocal類管理共享變量account
private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue(){
return 100;
}
};
public void save(int money){
account.set(account.get()+money);
}
public int getAccount(){
return account.get();
}
}
注:ThreadLocal與同步機(jī)制
a.ThreadLocal與同步機(jī)制都是為了解決多線程中相同變量的訪問沖突問題。
b.前者采用以"空間換時(shí)間"的方法士聪,后者采用以"時(shí)間換空間"的方式
阻塞隊(duì)列同步
前面同步方式都是在底層實(shí)現(xiàn)的線程同步,但是我們?cè)趯?shí)際開發(fā)當(dāng)中猛蔽,應(yīng)當(dāng)盡量遠(yuǎn)離底層結(jié)構(gòu)剥悟。 使用javaSE5.0版本中新增的java.util.concurrent包將有助于簡(jiǎn)化開發(fā)。 本小節(jié)主要是使用LinkedBlockingQueue<E>來實(shí)現(xiàn)線程的同步 LinkedBlockingQueue<E>是一個(gè)基于已連接節(jié)點(diǎn)的曼库,范圍任意的blocking queue区岗。 隊(duì)列是先進(jìn)先出的順序(FIFO),關(guān)于隊(duì)列以后會(huì)詳細(xì)講解~LinkedBlockingQueue 類常用方法 LinkedBlockingQueue() : 創(chuàng)建一個(gè)容量為Integer.MAX_VALUE的LinkedBlockingQueue put(E e) : 在隊(duì)尾添加一個(gè)元素毁枯,如果隊(duì)列滿則阻塞 size() : 返回隊(duì)列中的元素個(gè)數(shù) take() : 移除并返回隊(duì)頭元素慈缔,如果隊(duì)列空則阻塞代碼實(shí)例: 實(shí)現(xiàn)商家生產(chǎn)商品和買賣商品的同步
注:BlockingQueue<E>定義了阻塞隊(duì)列的常用方法,尤其是三種添加元素的方法种玛,我們要多加注意藐鹤,當(dāng)隊(duì)列滿時(shí):
add()方法會(huì)拋出異常
offer()方法返回false
put()方法會(huì)阻塞
原子變量同步
需要使用線程同步的根本原因在于對(duì)普通變量的操作不是原子的。
那么什么是原子操作呢赂韵?原子操作就是指將讀取變量值娱节、修改變量值、保存變量值看成一個(gè)整體來操作即-這幾種行為要么同時(shí)完成祭示,要么都不完成肄满。在java的util.concurrent.atomic包中提供了創(chuàng)建了原子類型變量的工具類,使用該類可以簡(jiǎn)化線程同步质涛。其中AtomicInteger 表可以用原子方式更新int的值稠歉,可用在應(yīng)用程序中(如以原子方式增加的計(jì)數(shù)器),但不能用于替換Integer汇陆;可擴(kuò)展Number怒炸,允許那些處理機(jī)遇數(shù)字類的工具和實(shí)用工具進(jìn)行統(tǒng)一訪問。
AtomicInteger類常用方法:
AtomicInteger(int initialValue) : 創(chuàng)建具有給定初始值的新的
AtomicIntegeraddAddGet(int dalta) : 以原子方式將給定值與當(dāng)前值相加
get() : 獲取當(dāng)前值
代碼實(shí)例:
class Bank {
private AtomicInteger account = new AtomicInteger(100);
public AtomicInteger getAccount() {
return account;
}
public void save(int money) {
account.addAndGet(money);
}
}
補(bǔ)充--原子操作主要有:
對(duì)于引用變量和大多數(shù)原始變量(long和double除外)的讀寫操作瞬测;
對(duì)于所有使用volatile修飾的變量(包括long和double)的讀寫操作横媚。
另外,可以使用線程池進(jìn)行管理及優(yōu)化月趟。
我的相關(guān)文章推薦鏈接地址點(diǎn)擊跳轉(zhuǎn):線程優(yōu)化及線程池管理
歡迎加入QQ群聊灯蝴,一起探究學(xué)習(xí)流行技術(shù),騷客們還等什么孝宗!
作者:艾陽(yáng)丶
來源:CSDN
原文:https://blog.csdn.net/csdn_aiyang/article/details/65442540
版權(quán)聲明:本文為博主原創(chuàng)文章穷躁,轉(zhuǎn)載請(qǐng)附上博文鏈接!