synchronized實(shí)現(xiàn)與運(yùn)用

前言

最近在看并發(fā)編程藝術(shù)這本書咙崎,對看書的一些筆記及個人工作中的總結(jié)弟跑。

rewrwe.jpeg

在多線程并發(fā)編程中synchronized一直是元老級角色廊蜒,很多人都會稱呼它為重量級鎖。但是在jdk1.6各種優(yōu)化之后胯盯,有些情況它并不那么重了懈费。
synchronized可以在任意對象及方法上加鎖,而加鎖的這段代碼稱為"互斥區(qū)"或"臨界區(qū)"

對象鎖

/**
 * 對象鎖
 */
public class SynchronizedTest1 extends Thread {

    private int count = 5;

    // synchronized加鎖
    public synchronized void run() {
        count--;
        System.out.println(this.currentThread().getName() + " count = " + count);
    }

    public static void main(String[] args) {

        SynchronizedTest1 myThread = new SynchronizedTest1();
        Thread t1 = new Thread(myThread, "t1");
        Thread t2 = new Thread(myThread, "t2");
        Thread t3 = new Thread(myThread, "t3");
        Thread t4 = new Thread(myThread, "t4");
        Thread t5 = new Thread(myThread, "t5");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

結(jié)果:

t1 count = 4
t5 count = 3
t4 count = 2
t3 count = 1
t2 count = 0

總結(jié):
當(dāng)多個線程訪問SynchronizedTest1的run方法時博脑,以排隊的方式進(jìn)行處理(這里排隊是按照CPU分配的先后順序而定的)憎乙,一個線程想要執(zhí)行synchronized修飾的方法里的代碼:首先是嘗試獲得鎖,如果拿到鎖叉趣,執(zhí)行synchronized代碼體內(nèi)容泞边,拿不到鎖,這個線程就會不斷的嘗試獲得這把鎖疗杉,直到拿到為止阵谚,而且是多個線程同時去競爭這把鎖。(也就是會有鎖競爭的問題)烟具。
弊處:就是導(dǎo)致cpu的使用頻率過高梢什,更嚴(yán)重的情況導(dǎo)致宕機(jī),我們應(yīng)該在開發(fā)中避免多個線程搶一把鎖的問題朝聋。

多個線程多個鎖

public class SynchronizedTest2 {
    private int num = 0;

    public synchronized void printNum(String tag) {
        try {

            if (tag.equals("a")) {
                num = 100;
                System.out.println("tag a, set num over!");
                Thread.sleep(2000);
            } else {
                num = 200;
                System.out.println("tag b, set num over!");
            }

            System.out.println("tag " + tag + ", num = " + num);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //注意觀察run方法輸出順序
    public static void main(String[] args) {

        //倆個不同的對象,所以執(zhí)行printNum方法的時候就是二把鎖嗡午,一個對象一把鎖,所以二者互相不影響
        final SynchronizedTest2 test1 = new SynchronizedTest2();
        final SynchronizedTest2 test2 = new SynchronizedTest2();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test1.printNum("a");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.printNum("b");
            }
        });

        t1.start();
        t2.start();
    }
}

結(jié)果:

tag a, set num over!
tag b, set num over!
tag b, num = 200
tag a, num = 100

總結(jié):
倆個不同的對象,所以執(zhí)行printNum方法的時候就是二把鎖玖翅,一個對象一把鎖翼馆,所以二者互相不影響。

類級鎖
synchronized修飾靜態(tài)方法

public class SynchronizedTest3 {
    private static int num = 0;

    //synchronized修飾靜態(tài)關(guān)鍵字
    public static synchronized void printNum(String tag) {
        try {

            if (tag.equals("a")) {
                num = 100;
                System.out.println("tag a, set num over!");
                Thread.sleep(2500);
            } else {
                num = 200;
                System.out.println("tag b, set num over!");
            }

            System.out.println("tag " + tag + ", num = " + num);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 注意觀察run方法輸出順序
    public static void main(String[] args) {
        final SynchronizedTest3 m1 = new SynchronizedTest3();
        final SynchronizedTest3 m2 = new SynchronizedTest3();

        Thread t1 = new Thread(() -> m1.printNum("a"));

        Thread t2 = new Thread(() -> m2.printNum("b"));

        t1.start();
        t2.start();

    }
}
tag a, set num over!
tag a, num = 100
tag b, set num over!
tag b, num = 200

結(jié)果:
synchronized修飾的靜態(tài)方法的鎖金度,表示鎖定.class類应媚,類一級別的鎖(獨(dú)占.class類)。
實(shí)際工作中為了降低鎖的力度猜极,synchronized修飾代碼塊中姜,從而達(dá)到更好的性能。鎖是synchronized括號里配置的對象跟伏。
同步代碼塊

//使用synchronized修飾代碼塊丢胚,
public class SynchronizedTest4 {

    private Object obj = new Object();

    public void test() throws Exception{
        System.out.println(Thread.currentThread().getName()+":1111");
        Thread.sleep(10000);
        synchronized (obj){
            System.out.println(Thread.currentThread().getName()+":22222");
        }
        System.out.println(Thread.currentThread().getName()+":33333");
    }

    public static void main(String[] args) {
        final SynchronizedTest4 test4 = new SynchronizedTest4();
        new Thread(() -> {
            try {
                test4.test();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();

        new Thread(() -> {
            try {
                test4.test();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();
    }

}

結(jié)果:

t1:1111
t2:1111
t1:22222
t2:22222
t2:33333
t1:33333

總結(jié):
java中的每一個對象都可以作為鎖:

  • 對于普通同步方法,鎖的是當(dāng)前實(shí)列對象受扳。
  • 對于靜態(tài)同步方法携龟,鎖的是當(dāng)前類的Class對象。
  • 對于同步方法塊勘高,鎖是Synchonized括號里配置的對象峡蟋。

當(dāng)一個線程試圖訪問同步代碼塊時,它首先必須要得到鎖华望,退出或拋出異常時必須釋放鎖蕊蝗。

從JVM規(guī)范中可以看到Synchonized在JVM里的實(shí)現(xiàn)原理,JVM基于進(jìn)入和退出Monitor對象來實(shí)現(xiàn)方法同步和代碼塊同步赖舟,但兩者的實(shí)現(xiàn)細(xì)節(jié)不一樣蓬戚。代碼塊同步是使用monitorenter(監(jiān)視器鎖)和monitorexit指令實(shí)現(xiàn)的,而方法同步是使用另外一種方式實(shí)現(xiàn)的宾抓,同步方法中依靠方法修飾符上的 ACC_SYNCHRONIZED 實(shí)現(xiàn)子漩。細(xì)節(jié)在JVM規(guī)范里并沒有詳細(xì)說明。但是石洗,方法的同步同樣可以使用這兩個指令來實(shí)現(xiàn)痛单。

monitorenter指令是在編譯后插入到同步代碼塊的開始位置,而monitorexit是插入到方法結(jié)束處和異常處劲腿,JVM要保證每個monitorenter必須有對應(yīng)的monitorexit與之配對旭绒。任何對象都有一個monitor與之關(guān)聯(lián),當(dāng)且一個monitor被持有后焦人,它將處于鎖定狀態(tài)挥吵。線程執(zhí)行到monitorenter指令時,將會嘗試獲取對象所對應(yīng)的monitor的所有權(quán)花椭,即嘗試獲得對象的鎖忽匈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矿辽,隨后出現(xiàn)的幾起案子丹允,更是在濱河造成了極大的恐慌郭厌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雕蔽,死亡現(xiàn)場離奇詭異折柠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)批狐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門扇售,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嚣艇,你說我怎么就攤上這事承冰。” “怎么了食零?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵困乒,是天一觀的道長。 經(jīng)常有香客問我贰谣,道長顶燕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任冈爹,我火速辦了婚禮涌攻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘频伤。我一直安慰自己恳谎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布憋肖。 她就那樣靜靜地躺著因痛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岸更。 梳的紋絲不亂的頭發(fā)上鸵膏,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音怎炊,去河邊找鬼谭企。 笑死,一個胖子當(dāng)著我的面吹牛评肆,可吹牛的內(nèi)容都是我干的债查。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼瓜挽,長吁一口氣:“原來是場噩夢啊……” “哼盹廷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起久橙,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤俄占,失蹤者是張志新(化名)和其女友劉穎管怠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缸榄,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渤弛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碰凶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹿驼,死狀恐怖欲低,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畜晰,我是刑警寧澤砾莱,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站凄鼻,受9級特大地震影響腊瑟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜块蚌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一闰非、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧峭范,春花似錦财松、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至甜害,卻和暖如春舶掖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尔店。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工眨攘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嚣州。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓期犬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親避诽。 傳聞我的和親對象是個殘疾皇子龟虎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

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

  • Java8張圖 11、字符串不變性 12沙庐、equals()方法鲤妥、hashCode()方法的區(qū)別 13佳吞、...
    Miley_MOJIE閱讀 3,709評論 0 11
  • 概述 互斥訪問:synchronized可以保證在同一個時刻,只有一個線程可以執(zhí)行某個方法或者某個代碼塊(主要是對...
    jiangmo閱讀 577評論 0 1
  • 1. 概念引入 Java中每一個對象都可以作為鎖棉安,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ): 普通同步方法底扳,鎖是...
    Java旅行者閱讀 829評論 0 4
  • 2015年已經(jīng)過去很久了,本來這篇文章應(yīng)該是在元旦之后就寫一寫的贡耽,然而自從4月份之后的很長一段時間都沒辦法很好的整...
    我是鴕鳥小姐閱讀 581評論 3 4
  • (孩稚~背帶)背帶一肩挑衷模,天晴街中過。這里車兒大蒲赂,那邊小狗遛阱冶。娃在帶上笑,娃在帶里睡滥嘴。游玩樂趣事木蹬,娃笑你也笑。
    甘朝武閱讀 118評論 0 0