JAVA\Android 多線程實(shí)現(xiàn)方式及并發(fā)與同步

概述
說到線程拭荤,就不得不先說線程和進(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)附上博文鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市问潭,隨后出現(xiàn)的幾起案子猿诸,更是在濱河造成了極大的恐慌,老刑警劉巖狡忙,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梳虽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灾茁,警方通過查閱死者的電腦和手機(jī)窜觉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來北专,“玉大人禀挫,你說我怎么就攤上這事⊥赝牵” “怎么了语婴?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)驶睦。 經(jīng)常有香客問我砰左,道長(zhǎng),這世上最難降的妖魔是什么啥繁? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任菜职,我火速辦了婚禮,結(jié)果婚禮上旗闽,老公的妹妹穿的比我還像新娘酬核。我一直安慰自己,他們只是感情好适室,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布嫡意。 她就那樣靜靜地躺著,像睡著了一般捣辆。 火紅的嫁衣襯著肌膚如雪蔬螟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天汽畴,我揣著相機(jī)與錄音旧巾,去河邊找鬼。 笑死忍些,一個(gè)胖子當(dāng)著我的面吹牛鲁猩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播罢坝,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼廓握,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起隙券,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤男应,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后娱仔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沐飘,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年拟枚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薪铜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恩溅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谓娃,到底是詐尸還是另有隱情脚乡,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布滨达,位于F島的核電站奶稠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捡遍。R本人自食惡果不足惜锌订,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望画株。 院中可真熱鬧辆飘,春花似錦、人聲如沸谓传。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)续挟。三九已至紧卒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诗祸,已是汗流浹背跑芳。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留直颅,地道東北人博个。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像际乘,于是被迫代替她去往敵國(guó)和親坡倔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容