Android多線程:手把手教你全面學(xué)習(xí)神秘的Synchronized關(guān)鍵字


前言

  • Java中,有一個(gè)常被忽略 但 非常重要的關(guān)鍵字Synchronized
  • 今天橙困,我將詳細(xì)講解 Java關(guān)鍵字Synchronized的所有知識(shí)哮兰,希望你們會(huì)喜歡

Carson帶你學(xué)多線程系列
基礎(chǔ)匯總
Android多線程:基礎(chǔ)知識(shí)匯總
基礎(chǔ)使用
Android多線程:繼承Thread類使用(含實(shí)例教程)
Android多線程:實(shí)現(xiàn)Runnable接口使用(含實(shí)例教程)
復(fù)合使用
Android多線程:AsyncTask使用教程(含實(shí)例講解)
Android多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實(shí)例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實(shí)例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學(xué)
相關(guān)使用
Android異步通信:這是一份全面&詳細(xì)的Handler機(jī)制學(xué)習(xí)攻略
Android多線程:手把手教你全面學(xué)習(xí)神秘的Synchronized關(guān)鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal


目錄

示意圖

1. 定義

Java中的1個(gè)關(guān)鍵字


2. 作用

保證同一時(shí)刻最多只有1個(gè)線程執(zhí)行 被Synchronized修飾的方法 / 代碼

其他線程 必須等待當(dāng)前線程執(zhí)行完該方法 / 代碼塊后才能執(zhí)行該方法 / 代碼塊


3. 應(yīng)用場(chǎng)景

保證線程安全,解決多線程中的并發(fā)同步問題(實(shí)現(xiàn)的是阻塞型并發(fā))肖抱,具體場(chǎng)景如下:

  1. 修飾 實(shí)例方法 / 代碼塊時(shí)奋刽,(同步)保護(hù)的是同一個(gè)對(duì)象方法的調(diào)用 & 當(dāng)前實(shí)例對(duì)象
  2. 修飾 靜態(tài)方法 / 代碼塊時(shí)瓦侮,(同步)保護(hù)的是 靜態(tài)方法的調(diào)用 & class 類對(duì)象

4. 原理

  1. 依賴 JVM 實(shí)現(xiàn)同步
  2. 底層通過一個(gè)監(jiān)視器對(duì)象(monitor)完成, wait()杨名、notify() 等方法也依賴于 monitor 對(duì)象

監(jiān)視器鎖(monitor)的本質(zhì) 依賴于 底層操作系統(tǒng)的互斥鎖(Mutex Lock)實(shí)現(xiàn)


5. 具體使用

Synchronized 用于 修飾 代碼塊脏榆、類的實(shí)例方法 & 靜態(tài)方法

5.1 鎖的類型 & 等級(jí)

  • 由于Synchronized 會(huì)修飾 代碼塊、類的實(shí)例方法 & 靜態(tài)方法台谍,故分為不同鎖的類型
  • 具體如下
示意圖
  • 之間的區(qū)別
示意圖

5.2 使用規(guī)則

示意圖

5.3 使用方式

/**
 * 對(duì)象鎖
 */
    public class Test{ 
    // 對(duì)象鎖:形式1(方法鎖) 
    public synchronized void Method1(){ 
        System.out.println("我是對(duì)象鎖也是方法鎖"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 
 
    // 對(duì)象鎖:形式2(代碼塊形式) 
    public void Method2(){ 
        synchronized (this){ 
            System.out.println("我是對(duì)象鎖"); 
            try{ 
                Thread.sleep(500); 
            } catch (InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 
 
    } 
 }

/**
 * 方法鎖(即對(duì)象鎖中的形式1)
 */
    public synchronized void Method1(){ 
        System.out.println("我是對(duì)象鎖也是方法鎖"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 

/**
 * 類鎖
 */
public class Test{ 
   // 類鎖:形式1 :鎖靜態(tài)方法
    public static synchronized void Method1(){ 
        System.out.println("我是類鎖一號(hào)"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 
 
    // 類鎖:形式2 :鎖靜態(tài)代碼塊
    public void Method2(){ 
        synchronized (Test.class){ 
            System.out.println("我是類鎖二號(hào)"); 
            try{ 
                Thread.sleep(500); 
            } catch (InterruptedException e){ 
                e.printStackTrace(); 
            } 
 
        } 
 
    } 
}

5.4 特別注意

Synchronized修飾方法時(shí)存在缺陷:若修飾1個(gè)大的方法,將會(huì)大大影響效率

  • 示例
    若使用Synchronized關(guān)鍵字修飾 線程類的run(),由于run()在線程的整個(gè)生命期內(nèi)一直在運(yùn)行趁蕊,因此將導(dǎo)致它對(duì)本類任何Synchronized方法的調(diào)用都永遠(yuǎn)不會(huì)成功

  • 解決方案
    使用 Synchronized關(guān)鍵字聲明代碼塊

該解決方案靈活性高:可針對(duì)任意代碼塊 & 任意指定上鎖的對(duì)象

代碼如下
  synchronized(syncObject) { 
    // 訪問或修改被鎖保護(hù)的共享狀態(tài) 
    // 上述方法 必須 獲得對(duì)象 syncObject(類實(shí)例或類)的鎖
}

6. 特點(diǎn)

示意圖

注:原子性坞生、可見性、有序性的定義

示意圖

7. 其他控制并發(fā) / 線程同步方式

7.1 Lock掷伙、ReentrantLock

  • 簡(jiǎn)介
示意圖
  • 區(qū)別
示意圖

7.2 CAS

7.2.1 定義

Compare And Swap是己,即 比較 并 交換,是一種解決并發(fā)操作的樂觀鎖

synchronized鎖住的代碼塊:同一時(shí)刻只能由一個(gè)線程訪問任柜,屬于悲觀鎖

7.2.2 原理
// CAS的操作參數(shù)
內(nèi)存位置(A)
預(yù)期原值(B)
預(yù)期新值(C)

// 使用CAS解決并發(fā)的原理:
// 1. 首先比較A卒废、B,若相等宙地,則更新A中的值為C摔认、返回True;若不相等宅粥,則返回false参袱;
// 2. 通過死循環(huán),以不斷嘗試嘗試更新的方式實(shí)現(xiàn)并發(fā)

// 偽代碼如下
public boolean compareAndSwap(long memoryA, int oldB, int newC){
    if(memoryA.get() == oldB){
        memoryA.set(newC);
        return true;
    }
    return false;
}


7.2.3 優(yōu)點(diǎn)

資源耗費(fèi)少:相對(duì)于synchronized秽梅,省去了掛起線程抹蚀、恢復(fù)線程的開銷

但,若遲遲得不到更新企垦,死循環(huán)對(duì)CPU資源也是一種浪費(fèi)

7.2.4 具體實(shí)現(xiàn)方式
  • 使用CAS有個(gè)“先檢查后執(zhí)行”的操作
  • 而這種操作在Java中是典型的不安全的操作环壤,所以 CAS在實(shí)際中是C++通過調(diào)用CPU指令實(shí)現(xiàn)的
  • 具體過程
// 1. CAS在Java中的體現(xiàn)為Unsafe類
// 2. Unsafe類會(huì)通過C++直接獲取到屬性的內(nèi)存地址
// 3. 接下來CAS由C++的Atomic::cmpxchg系列方法實(shí)現(xiàn)
7.2.5 典型應(yīng)用:AtomicInteger

對(duì) i++ 與 i--,通過compareAndSet & 一個(gè)死循環(huán)實(shí)現(xiàn)

compareAndSet函數(shù)內(nèi)部 = 通過jni操作CAS指令钞诡。直到CAS操作成功跳出循環(huán)

   private volatile int value; 
    /** 
     * Gets the current value. 
     * 
     * @return the current value 
     */ 
    public final int get() { 
        return value; 
    } 
    /** 
     * Atomically increments by one the current value. 
     * 
     * @return the previous value 
     */ 
    public final int getAndIncrement() { 
        for (;;) { 
            int current = get(); 
            int next = current + 1; 
            if (compareAndSet(current, next)) 
                return current; 
        } 
    } 
 
    /** 
     * Atomically decrements by one the current value. 
     * 
     * @return the previous value 
     */ 
    public final int getAndDecrement() { 
        for (;;) { 
            int current = get(); 
            int next = current - 1; 
            if (compareAndSet(current, next)) 
                return current; 
        } 
    }

8. 總結(jié)

  • 本文主要對(duì)Java中常被忽略 但 非常重要的關(guān)鍵字Synchronized進(jìn)行講解
  • 下一篇文章我將對(duì)講解Android多線程的相關(guān)知識(shí)镐捧,感興趣的同學(xué)可以繼續(xù)關(guān)注Carson_Ho的簡(jiǎn)書

Carson帶你學(xué)多線程系列
基礎(chǔ)匯總
Android多線程:基礎(chǔ)知識(shí)匯總
基礎(chǔ)使用
Android多線程:繼承Thread類使用(含實(shí)例教程)
Android多線程:實(shí)現(xiàn)Runnable接口使用(含實(shí)例教程)
復(fù)合使用
Android多線程:AsyncTask使用教程(含實(shí)例講解)
Android多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實(shí)例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實(shí)例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學(xué)
相關(guān)使用
Android異步通信:這是一份全面&詳細(xì)的Handler機(jī)制學(xué)習(xí)攻略
Android多線程:手把手教你全面學(xué)習(xí)神秘的Synchronized關(guān)鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal


歡迎關(guān)注Carson_Ho的簡(jiǎn)書

不定期分享關(guān)于安卓開發(fā)的干貨,追求短臭增、平懂酱、快,但卻不缺深度誊抛。


請(qǐng)點(diǎn)贊列牺!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拗窃,一起剝皮案震驚了整個(gè)濱河市瞎领,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌随夸,老刑警劉巖九默,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宾毒,居然都是意外死亡驼修,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乙各,“玉大人墨礁,你說我怎么就攤上這事《停” “怎么了恩静?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蹲坷。 經(jīng)常有香客問我驶乾,道長(zhǎng),這世上最難降的妖魔是什么循签? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任级乐,我火速辦了婚禮,結(jié)果婚禮上懦底,老公的妹妹穿的比我還像新娘唇牧。我一直安慰自己,他們只是感情好聚唐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布丐重。 她就那樣靜靜地躺著,像睡著了一般杆查。 火紅的嫁衣襯著肌膚如雪扮惦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天亲桦,我揣著相機(jī)與錄音崖蜜,去河邊找鬼。 笑死客峭,一個(gè)胖子當(dāng)著我的面吹牛豫领,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舔琅,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼等恐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了备蚓?” 一聲冷哼從身側(cè)響起课蔬,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤父丰,失蹤者是張志新(化名)和其女友劉穎咸包,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缩挑,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡流昏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年扎即,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吞获。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铺遂,死狀恐怖衫哥,靈堂內(nèi)的尸體忽然破棺而出茎刚,到底是詐尸還是另有隱情襟锐,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布膛锭,位于F島的核電站粮坞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏初狰。R本人自食惡果不足惜莫杈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奢入。 院中可真熱鬧筝闹,春花似錦、人聲如沸腥光。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽武福。三九已至议双,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捉片,已是汗流浹背平痰。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伍纫,地道東北人宗雇。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像莹规,于是被迫代替她去往敵國(guó)和親赔蒲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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