關(guān)于鎖

我對(duì)于鎖的初次接觸和簡(jiǎn)單理解

定義一個(gè)商店Shop類

public class Shop {
    public void watch() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + ":" + "看完了舟山!");
        Thread.sleep(2000);
    }

    public void buy() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始買商品掩浙!");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + ":" + "買完了");
        Thread.sleep(2000);
    }
}

這個(gè)類中有兩個(gè)方法赖临,每個(gè)方法都可以輸出兩次當(dāng)前線程名和對(duì)應(yīng)語(yǔ)句星立。為了方便區(qū)分爽茴,在這兩個(gè)輸出語(yǔ)句之間加上2秒的間隔。

public class About_LockTest {
    public static void main(String[] args) {
        //實(shí)例化一個(gè)Shop對(duì)象 sp
        Shop sp = new Shop();
        //匿名內(nèi)部類使得t0和t1都執(zhí)行sp中的watch方法
        Thread t0 = new Thread(() -> {
            try {
                sp.watch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t1 = new Thread(() -> {
            try {
                sp.watch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t0.start();
        t1.start();
    }
}

運(yùn)行該程序绰垂,發(fā)現(xiàn)t0和t1同時(shí)輸出相應(yīng)語(yǔ)句室奏,這表明兩個(gè)線程在同時(shí)運(yùn)行。如果劲装,對(duì)watch方法加上鎖胧沫,那么再運(yùn)行該程序會(huì)有什么結(jié)果呢?

public synchronized void watch() throws InterruptedException {//在public后面加上synchronized
        System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + ":" + "看完了!");
        Thread.sleep(2000);
    }

此時(shí)占业,通過(guò)輸出線程名可以發(fā)現(xiàn)绒怨,只有一個(gè)線程在運(yùn)行,而另一個(gè)線程沒(méi)有運(yùn)行纺酸,也就是處于阻塞狀態(tài)窖逗。直接在方法名前面加上synchronized關(guān)鍵詞,其實(shí)等價(jià)于以下語(yǔ)句

public void watch() throws InterruptedException {
        synchronized (this) {//將整個(gè)方法體包裹在鎖內(nèi)餐蔬,其中用this碎紊,本類對(duì)象作為鑰匙
            System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":" + "看完了!");
            Thread.sleep(2000);
        }
    }

? 線程在執(zhí)行這個(gè)方法的時(shí)候樊诺,被鎖住的部分必須要鑰匙才能進(jìn)入仗考,每個(gè)鑰匙只能同時(shí)被一個(gè)線程持有。在這里鑰匙是本類對(duì)象词爬,而在上面都是利用sp對(duì)象調(diào)用方法秃嗜,所以鑰匙就是sp。這個(gè)持有sp的狀態(tài)顿膨,會(huì)一直持續(xù)到線程在走出synchronized包裹的范圍前锅锨,此時(shí)沒(méi)拿到鑰匙sp的線程只能在鎖外排隊(duì),處于阻塞狀態(tài)恋沃。等到一個(gè)線程走出synchro-nized的作用域之后必搞,就會(huì)釋放手中的鑰匙sp,此時(shí)鑰匙處于自由狀態(tài)囊咏,而另一個(gè)線程會(huì)得到這把鑰匙恕洲,于是可以進(jìn)入這個(gè)鎖住的區(qū)域塔橡,可以執(zhí)行里面的代碼。

? 為了驗(yàn)證以上觀點(diǎn)霜第,我對(duì)Thread t1進(jìn)行改寫:

1葛家、鎖只作用于自己的作用域

Thread t1 = new Thread(() -> {
            try {
                sp.buy();//添加一個(gè)buy方法在watch方法前面
                sp.watch;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

運(yùn)行程序后,發(fā)現(xiàn)t0在執(zhí)行watch方法的同時(shí)泌类,t1也在執(zhí)行buy方法癞谒,當(dāng)t0執(zhí)行完watch且t1執(zhí)行完buy之后,t1拿到t0的鎖末誓,繼續(xù)執(zhí)行watch方法扯俱。所以說(shuō),此處這把鎖只是鎖住了watch方法喇澡,對(duì)于buy方法而言迅栅,并無(wú)任何影響

2、同一把鑰匙只能同時(shí)被同一個(gè)線程持有(忽略釋放之后持有之前的自由狀態(tài))

將t0的watch方法刪去晴玖,只留有buy方法:

Thread t1 = new Thread(() -> {
            try {
                sp.buy();//此處t1只有buy方法了
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

將Shop類中的buy也加上synchronized鎖读存,這把鎖的鑰匙也是this本類對(duì)象,在目前認(rèn)仍是sp

public synchronized void buy() throws InterruptedException {//buy方法加鎖
        System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始買商品呕屎!");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + ":" + "買完了");
        Thread.sleep(2000);
    }

運(yùn)行程序后让簿,發(fā)現(xiàn)t0執(zhí)行watch方法時(shí),線程t1沒(méi)有任何動(dòng)作秀睛,而等到t0結(jié)束watch方法后尔当,才開(kāi)始執(zhí)行buy。由于之前已經(jīng)證明鎖只能作用于自己的作用域蹂安,所以排除了watch的鎖影響了buy(相反亦然)椭迎,這就說(shuō)明此處鑰匙只能同時(shí)被一個(gè)線程持有,只要等鑰匙釋放并拿到鑰匙后田盈,另一個(gè)線程才會(huì)執(zhí)行畜号。

3、只要持有鑰匙就可以打開(kāi)對(duì)應(yīng)鎖

(在2的基礎(chǔ)上)在Shop類中實(shí)例化一個(gè)Object對(duì)象obj允瞧,這里將watch方法鎖的鑰匙改為obj:

Object obj = new Object();//新生成一個(gè)obj

    public void watch() throws InterruptedException {
        synchronized (obj) {//將obj作為鑰匙
            System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":" + "看完了简软!");
            Thread.sleep(2000);
        }
    }

運(yùn)行程序發(fā)現(xiàn),t0和t1分別同時(shí)運(yùn)行watch和buy方法述暂。由1和2可以知道痹升,不會(huì)是二者同時(shí)持有鑰匙,并且因?yàn)椴煌i之間相互影響而導(dǎo)致線程同時(shí)運(yùn)行畦韭。這里是因?yàn)槭勇瑆atch方法使用了obj作為鑰匙,t0持有的是obj廊驼;buy使用了本類對(duì)象sp作為鑰匙据过。這兩個(gè)鑰匙并不相同,所以t0和t1都能直接拿到各自的鑰匙(沒(méi)有其他線程競(jìng)爭(zhēng))妒挎,打開(kāi)對(duì)應(yīng)的鎖執(zhí)行方法绳锅。

4、調(diào)用不同對(duì)象的多線程的同步

新創(chuàng)建一個(gè)Shop對(duì)象shp酝掩,讓t0只調(diào)用shp的buy方法鳞芙,t1只調(diào)用原來(lái)sp的方法,將3中兩個(gè)鎖的鑰匙都改為this

public static void main(String[] args) {
        Shop sp = new Shop();
        Shop shp=new Shop();//再實(shí)例化一個(gè)shp
        Thread t0 = new Thread(() -> {
            try {
                shp.buy();//調(diào)用shp中的buy方法
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t1 = new Thread(() -> {
            try {
                sp.buy();//調(diào)用sp中的buy方法
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t0.start();
        t1.start();
    }
/**兩個(gè)方法都以this作為鑰匙*/
public void watch() throws InterruptedException {
        synchronized (this) {
            System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":" + "看完了期虾!");
            Thread.sleep(2000);
        }
    }

    public synchronized void buy() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始買商品原朝!");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + ":" + "買完了");
        Thread.sleep(2000);
    }

執(zhí)行程序后發(fā)現(xiàn)t0和t1同時(shí)各自執(zhí)行buy方法,因?yàn)樗麄兊蔫€匙shp镶苞、sp都直接被持有喳坠,無(wú)需等待。如果在這種情況下同步t0和t1茂蚓,可以在類中創(chuàng)建一個(gè)靜態(tài)對(duì)象作為鑰匙:

static Object obj = new Object();//靜態(tài)對(duì)象
//都以靜態(tài)對(duì)象為鑰匙
    public void watch() throws InterruptedException {
        synchronized (obj) {
            System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始看商品");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":" + "看完了壕鹉!");
            Thread.sleep(2000);
        }
    }

    public void buy() throws InterruptedException {
        synchronized (obj) {
            System.out.println(Thread.currentThread().getName() + ":" + "開(kāi)始買商品!");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":" + "買完了");
            Thread.sleep(2000);
        }
    }

靜態(tài)對(duì)象是類所有對(duì)象共享的聋涨,所以不管有多少個(gè)對(duì)象晾浴,在這個(gè)類都只有一個(gè)靜態(tài)對(duì)象可用,這個(gè)鑰匙就唯一了牍白,所以執(zhí)行程序后一個(gè)線程先執(zhí)行buy脊凰,之后另一個(gè)線程才執(zhí)行buy。

總結(jié)

鎖的作用范圍是有限的(可自定義)茂腥,不同鎖對(duì)應(yīng)的鑰匙可以相同狸涌,相應(yīng)的這把鑰匙完全可以打開(kāi)這些鎖。同一把鑰匙同時(shí)只能被同一個(gè)線程持有础芍,并且只有這個(gè)持有鑰匙的線程可以執(zhí)行鎖內(nèi)代碼杈抢,沒(méi)有鑰匙的線程就處于阻塞狀態(tài),等到持有鑰匙的線程走出鎖后仑性,會(huì)釋放鑰匙惶楼,這時(shí)就有機(jī)會(huì)得到鑰匙執(zhí)行代碼,沒(méi)有得到就繼續(xù)堵塞诊杆,等待下一次機(jī)會(huì)歼捐。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晨汹,隨后出現(xiàn)的幾起案子豹储,更是在濱河造成了極大的恐慌,老刑警劉巖淘这,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剥扣,死亡現(xiàn)場(chǎng)離奇詭異巩剖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)钠怯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門佳魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人晦炊,你說(shuō)我怎么就攤上這事鞠鲜。” “怎么了断国?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵贤姆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我稳衬,道長(zhǎng)霞捡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任宋彼,我火速辦了婚禮弄砍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘输涕。我一直安慰自己音婶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布莱坎。 她就那樣靜靜地躺著衣式,像睡著了一般。 火紅的嫁衣襯著肌膚如雪檐什。 梳的紋絲不亂的頭發(fā)上碴卧,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音乃正,去河邊找鬼住册。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瓮具,可吹牛的內(nèi)容都是我干的荧飞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼名党,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叹阔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起传睹,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耳幢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后欧啤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體睛藻,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡启上,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了修档。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碧绞。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吱窝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迫靖,我是刑警寧澤院峡,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站系宜,受9級(jí)特大地震影響照激,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盹牧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一俩垃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汰寓,春花似錦口柳、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至毛好,卻和暖如春望艺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肌访。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工找默, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吼驶。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓惩激,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親旨剥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咧欣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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