synchronized使用

synchronized是一種同步鎖。他修飾的對象有一下幾種:

  • 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊演训,其作用的范圍是大括號括起來的代碼弟孟,作用的對象是調(diào)用這個代碼塊的對象。
  • 修飾一個方法仇祭,被修飾的方法稱為同步語句塊披蕉,其作用的范圍是整個方法,作用的對象是調(diào)用這個方法的對象乌奇。
  • 修飾一個靜態(tài)的方法,其作用是整個靜態(tài)方法眯娱,作用的對象是這個類的所有對象礁苗。
  • 修飾一個類,其作用的范圍是synchronized后面括號括起來的部分徙缴,主作用的對象是這個類的所有對象试伙。

修飾一個代碼塊

  • 一個線程訪問一個對象中的同步代碼塊時:
class SyncThread impltements Runnable{
    private static final count;
    public SyncThread(){
        count = 0;    
    }
    public void run(){
        synchronized(this){
            for(int i = 0;i<5;i++){
               try{
                System.out.println(Thread.currentThead().getName()+":"+(count++))
                Thread.sleep(100);
               }catch(....){
                .......
               } 
            }    
        }
    }
    public int getCount(){
        return count;
    }
    SyncThread syncThread = new SyncThread();
    Thread thread1 = new Thread(syncThread, "11");
    Thread thread2 = new Thread(syncThread, "22");
    thread1.start();
    thread2.start();
}

運(yùn)行結(jié)果:
11:0
11:1
11:2
11:3
11:4
22:5
22:6
22:7
22:8
22:9

當(dāng)兩個并發(fā)線程同時訪問同一個對象中的同步代碼塊時嘁信,在同一時刻只能有一個線程得到執(zhí)行,另一個線程受到阻塞疏叨,必須等待當(dāng)前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊潘靖。
但是當(dāng)我們把運(yùn)行代碼改一下:

Thread thread1 = new Thread(new SyncThread(),"11");
Thread thread2 = new Thread(new SyncThread(), "22");
thread1.start();
thread2.start();

運(yùn)行結(jié)果:
11:0
22:1
11:2
22:3
11:4
22:5
22:6
11:7
11:8
22:9

因?yàn)橐陨洗a中synchronized鎖定的是對象,這時會有兩把鎖分別鎖定對象1和對象2蚤蔓,而這兩把鎖時互不干擾的卦溢,不形成互斥,所以兩個線程可以同時執(zhí)行秀又。
2.當(dāng)一個線程訪問對象的一個同步代碼塊時单寂,另一個線程仍然可以同時訪問該對象中的非synchronized同步代碼塊。3.指定要給某個對象加鎖

class Account{
    String name;
    int amount;
    
    public Account(String name, int amount){
        this.name = name;
        this.amount = amount;
    }
    
    //存錢
    public void deposit(int amt){
        amount += amt;
        try{
            Thread.sleep(100);
        }catch(...){
            ....
        }
    }
    
    //取錢
    public void withdraw(int amt){
        amount -= amt;
        try{
            Thread.sleep(100);
        }catch(...){
            ...
        }
    }
    
    public int getAmount(){
        return amount;
    }
}

class AccountOperator implements Runnable{
    
    private Account account;
    
    public void run(){
        synchronized(account){
            account.deposit(500);
            account.withdraw(500);
            System.out.println(Thread.currentThread().getName() + ":" + account.getAmount());
        }
    }
}

//調(diào)用代碼
Account account = new Account("zhangsan", 10000);
AccountOperator accountOperator = new AccountOperator(account);
final int THREAD_NUM = 5;
Thread[] threads = new Thread[THREAD_NUM];
for(int i = 0;i<THREAD_NUM;i++){
    thread[i] = new Thread(accountOperator, "thread"+i);
    thread[i].start();
}

運(yùn)行結(jié)果:
Thread3:10000
Thread2:10000
Thread1:10000
Thread4:10000
Thread0:10000

AccountOperator類的run方法中吐辙,我們用synchronizedaccount對象加了鎖宣决。這時,當(dāng)一個線程訪問account對象時昏苏,其他試圖訪問account對象的線程將會阻塞尊沸,知道該線程訪問account對象結(jié)束。
當(dāng)一個有明確的對象作為?鎖時贤惯,就可以用類似下面:

public void method3(SomeObject obj){
    //obj鎖定的對象
    synchronized(obj){
        //todo
    }
}

當(dāng)沒有明確的對象作為鎖椒丧,只是想讓一段代碼同步時,可以創(chuàng)建一個特殊的對象來充當(dāng)鎖:

class Test implements Runnable{
    
    private byte[] lock = new byte[0];
    
    public void method(){
        synchronized(lock){
            //todo
        }
    }
    
    public void run(){
    }
}

說明:零長度的byte數(shù)組對象創(chuàng)建起來比任何對象都經(jīng)濟(jì):生成零長度的byte[]對象只需3條操作碼救巷,而Object lock = new Object()則需要7行操作碼壶熏。
修飾一個方法

public synchronized void run(){

    for(int i = 0;i<5;i++){
        try{
            System.out.println(Thread.currentThread().getName() + ":" + (count++));
         Thread.sleep(100);
        }catch(...){
            ...
        }
    }
    
}

synchronized作用于整個方法的寫法:

public synchronized void method(){
    //todo
}

或者
public void method(){

    synchronized(this){
        //todo
    }
    
}

在用synchronized修飾方法時要注意一下幾點(diǎn):

1.synchronized關(guān)鍵字不能繼承。
2.在定義接口方法時不能使用synchronized關(guān)鍵字
3.構(gòu)造方法不能使用synchronized關(guān)鍵字浦译,但可以使用sync hronized代碼塊來進(jìn)行同步棒假。
修飾一個靜態(tài)方法

public synchronized static void method(){
    //todo
}

我們知道靜態(tài)方法屬于類而不屬于對象的。同樣的精盅,synchronized修飾的靜態(tài)方法鎖定的是這個類的所有對象帽哑。

class SyncThread implements Runnable{

    private static int count;
    
    public SyncThread(){
        count = 0;
    }
    
    public synchronized void run(){
    }
    
    public synchronized static void method(){
        for(int i = 0;i<5;i++){
            try{
                Log.e(TAG, "method: "+Thread.currentThread().getName()+":"+(count++));
                Thread.sleep(100);
            }catch(...){
                ...
            }
        }
    }
}

調(diào)用代碼:
SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(sychThread1, "SyncThread1");
Thread thread2 = new Thread(sychThread2, "SyncThread2");
thread1.start();
thread2.start();

運(yùn)行結(jié)果:
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

syncThread1syncThread2SyncThread的兩個對象叹俏,但在thread1thread2并發(fā)執(zhí)行卻保持了線程同步妻枕,因?yàn)?code>run中調(diào)用了靜態(tài)方法method,而靜態(tài)方法是屬于類的粘驰,所以syncThread1syncThread2相當(dāng)于同一把鎖屡谐。
修飾一個類

class ClassName{

    public void method(){
        synchronized(ClassName.class){
            //todo
        }
    }
    
}

class SyncThread implements Runnable{

    private static int count;
    
    public SyncThread(){
        count = 0;
    }
    
    public void run(){
        method();
    }
    
    public static void method(){
        synchronized(SyncThread.class){
            for(int i = 0; i<5;i++){
                try{
                    log.e(TAG, "run: "+Thread.currentThread().getName()+":"+count++);
                    Thread.sleep(100);
                }catch(...){
                    ...
                }
            }
        }
    }
}

運(yùn)行結(jié)果:
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9

總結(jié):1.無論synchronized關(guān)鍵字加在方法還是對象上,如果他作用的對象是非靜態(tài)的蝌数,則它取得的鎖是對象愕掏,如果synchronized作用的對象是一個靜態(tài)方法或一個類,則它取得的鎖是類顶伞,該類所有的對象同一把鎖饵撑。
2.每個對象只有一個鎖(lock)與之關(guān)聯(lián)剑梳,誰拿到這個鎖誰就可以運(yùn)行它所控制的那段代碼。
3.實(shí)現(xiàn)同步時要很大的系統(tǒng)開銷作為代價的滑潘,甚至可能造成死鎖垢乙,所以盡量避免無謂的同步控制。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末语卤,一起剝皮案震驚了整個濱河市追逮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粱侣,老刑警劉巖羊壹,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異齐婴,居然都是意外死亡油猫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門柠偶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來情妖,“玉大人,你說我怎么就攤上這事诱担≌敝ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵蔫仙,是天一觀的道長料睛。 經(jīng)常有香客問我,道長摇邦,這世上最難降的妖魔是什么恤煞? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮施籍,結(jié)果婚禮上居扒,老公的妹妹穿的比我還像新娘。我一直安慰自己丑慎,他們只是感情好喜喂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竿裂,像睡著了一般玉吁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铛绰,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天诈茧,我揣著相機(jī)與錄音,去河邊找鬼捂掰。 笑死敢会,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的这嚣。 我是一名探鬼主播鸥昏,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姐帚!你這毒婦竟也來了吏垮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤罐旗,失蹤者是張志新(化名)和其女友劉穎膳汪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體九秀,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遗嗽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鼓蜒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹换。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖都弹,靈堂內(nèi)的尸體忽然破棺而出娇豫,到底是詐尸還是另有隱情,我是刑警寧澤畅厢,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布冯痢,位于F島的核電站,受9級特大地震影響框杜,放射性物質(zhì)發(fā)生泄漏浦楣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一霸琴、第九天 我趴在偏房一處隱蔽的房頂上張望椒振。 院中可真熱鬧,春花似錦梧乘、人聲如沸澎迎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夹供。三九已至,卻和暖如春仁堪,著一層夾襖步出監(jiān)牢的瞬間哮洽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工弦聂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸟辅,地道東北人氛什。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像匪凉,于是被迫代替她去往敵國和親枪眉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355