關(guān)于synchronized的參數(shù)及其含義
這個想必大家都不陌生,java里面的重量級鎖。用來控制線程安全的。在long And long ,我剛開始接觸java的時候 ,我就對這個關(guān)鍵詞好奇頗深。尤其是 它的參數(shù),有this的 也有靜態(tài)變量的。網(wǎng)上對這個參數(shù)解釋又太過術(shù)語話。
例如
作用于方法時,鎖住的是對象的實例(this);
當(dāng)作用于靜態(tài)方法時,鎖住的是Class實例,又因為Class的相關(guān)數(shù)據(jù)存儲在永久帶PermGen(jdk1.8則是metaspace),永久帶是全局共享的,因此靜態(tài)方法鎖相當(dāng)于類的一個全局鎖,會鎖所有調(diào)用該方法的線程;
當(dāng)作用于一個靜態(tài)類的時候,不管是不是本身內(nèi)部的靜態(tài)類,還是別人的靜態(tài)類,都可以完成鎖住的效果(ps 上鎖的時候,相當(dāng)于一群人 拿把鎖找個東西上鎖
synchronized作用于一個對象實例時,鎖住的是所有以該對象為鎖的代碼塊。
這不管是對于初學(xué)者,還是老鳥 。都感覺沉長無味。
最近,我的項目涉及到這一塊,我對這個方法有了頓悟,寫下來 傳之后世
我對這個參數(shù)的理解是這樣的。
synchronized(獲取鎖的地方){ 工作內(nèi)容 }
是的 ,你們沒看錯 ()里面的就是一個“獲取鎖的地方”。{ }里面是工作內(nèi)容。 他們有這幾條關(guān)系。
- 獲取鎖的地方 和 工作內(nèi)容 是不必需要 有任何關(guān)聯(lián)的。 可以有關(guān)聯(lián),但沒有關(guān)聯(lián) 也沒事
- 獲取鎖的地方 :只是一個讓synchronized 整體 放置鎖的地方,一個“獲取鎖的地方” 只有一把鎖。**
- 工作內(nèi)容: 要進(jìn)行工作的**前提是 synchronized整體,找到一個“獲取鎖的地方”,在 “獲取鎖的地方” 獲取到了鎖, 如果 “獲取鎖的地方”的鎖,已經(jīng)被別人拿去了,那么就只能等待別人 把鎖還給 “獲取鎖的地方”。然后 再獲取鎖。
- synchronized 會使用運行工作內(nèi)容的前提,必須獲取到鎖。這個意思呢,就是例如,當(dāng)前線程synchronized 獲取到了objec A的鎖,那么其他線程還可以更改 A 進(jìn)行操作么?。 這個得到分兩種情況,如果其他線程代碼 是被synchronized 所包裹的,那么只能等 objec A被釋放了,才能更改。如果,其他線程代碼沒有被synchronized包裹,她可以不需要有鎖,就可以對objec A進(jìn)行操作。
解釋
先打個比方,我們把 synchronized這個看成一個整體,那么在多線程的時候,就會有很多個 synchronized整體。 這個整體開始工作的前提是 它可以從 “獲取鎖的地方”拿到鎖。那么他就可以做工作了。如果 想要 “獲取鎖的地方”的鎖,已經(jīng)被別人拿走了。那么只能等別人把鎖換回來,才行。。
上面這個還是有點抽象。就這么說吧 在程序運行多線程的,會產(chǎn)生好多synchronized整體。就叫小明,小紅,小芳,小花…等。他們現(xiàn)在手中沒有鎖,只有手中有鎖的時候 才可以工作。 現(xiàn)在小明,小紅他們來到工作的地方。獲取鎖的地方就是路邊的一棵樹::注意現(xiàn)在路邊只有這一棵樹。小紅搶先一步將樹上的鎖拿走了。然后小紅工作去了(她的工作 不用和樹有關(guān)系,她可以砍樹,也可以去路邊掃地 )。小明,小芳等其他人,因為沒地方獲取鎖(只有一棵樹 并且樹的鎖 已經(jīng)被小紅拿走了)。所以只能在原地等待 ,小紅工作做完了 把鎖還給樹 ,小明,小芳才有機會進(jìn)行工作。、
注意: 上面是路邊只有一棵樹,如果存在好幾顆樹的話,那么小明,小紅他們就可以同時放置獲取鎖 一個數(shù)對應(yīng)一個鎖,多個樹就多個鎖。這個對應(yīng)于類的實例 (實例可以有好多個)
驗證
我們首先定義一個Runnable ,因為 多線程的話 最好還是用Runnable,至于為什么呢?百度去。
static class LockRunable implements Runnable { private int num; private LockNormal lockNormal; public LockRunable(int num, LockNormal lockNormal) { this.num = num; this.lockNormal = lockNormal; } @Override public void run() { while (true) { if (num <= 0) { break; } try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + num--); } } }
這個類呢 接受一個整數(shù),一個LockNormal我自己定義的類,在run里面呢先對 num進(jìn)行判斷小于等于0的話,就退出,否則減一。 運行一下
LockNormal lockNormal = new LockNormal(); LockRunable one = new LockRunable(15, lockNormal); new Thread(one).start(); new Thread(one).start(); new Thread(one).start(); new Thread(one).start(); new Thread(one).start();
num竟然變成負(fù)的了,這是因為 五個線程同時對他進(jìn)行操作,造成的。要避免這種情況,只能一個線程操作的時候,別的線程就不能操作。
我們給程序加鎖試一下。首先定義一個 靜態(tài)成員,靜態(tài)成員有一個特點是系統(tǒng)初始化的,全局只有一個實例。就相當(dāng)于上面的 只有一棵樹。
static final transient Object lock = new Object();
對 工作內(nèi)容加鎖
@Override public void run() { while (true) { synchronized (lock) { if (num <= 0) { break; } try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + num--); } } } }
運行
這次就和預(yù)期結(jié)果相等了。但是 我們可發(fā)現(xiàn) 都是都是同一個線程進(jìn)行操作的,這是因為 sleep時候不會釋放鎖,其他線程也無法進(jìn)行操作
傳入實例
static class LockRunable implements Runnable { private int num; private LockNormal lockNormal; public LockRunable(int num, LockNormal lockNormal) { this.num = num; this.lockNormal = lockNormal; } @Override public void run() { while (true) { synchronized (lockNormal) { if (num <= 0) { break; } try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + num--); } } } }
結(jié)果:
也是同樣的結(jié)果,如果 我們傳入this的話 運行還是一樣的結(jié)果。這就是上面樹的問題了,不管是傳入的實例,還是this本身實例。只有能保證它們本身是唯一的,也就是“獲取鎖的地方”只有一個,同一時間內(nèi)只有一個人能成功獲取到鎖 進(jìn)行工作。就和鎖靜態(tài)成員是一樣的效果如果我們 new 兩個Runnable的話,并且傳入this實例的話,就會有兩個“獲取鎖的地方” ,可以有兩個人同時工作。
總結(jié)
synchronized(放鎖的地方){ 工作內(nèi)容 }
只要我們保證“獲取鎖的地方”是唯一的,那么在同一時刻,就只能有一個工作內(nèi)容會被執(zhí)行。如果,“獲取鎖的地方”不是唯一的(一個類new很多實例,鎖住this實例,那么同一時刻就會有很多放鎖的地方),在同一時刻就會有好多 工作內(nèi)容被執(zhí)行。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決
這篇文章主要介紹了Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java中AIO、BIO、NIO應(yīng)用場景及區(qū)別
本文主要介紹了Java中AIO、BIO、NIO應(yīng)用場景及區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06利用spring?boot+WebSocket實現(xiàn)后臺主動消息推送功能
目前對于服務(wù)端向客戶端推送數(shù)據(jù),常用技術(shù)方案有輪詢、websocket等,下面這篇文章主要給大家介紹了關(guān)于利用spring?boot+WebSocket實現(xiàn)后臺主動消息推送功能的相關(guān)資料,需要的朋友可以參考下2022-04-04MyBatis與SpringMVC相結(jié)合實現(xiàn)文件上傳、下載功能
這篇文章主要介紹了MyBatis與SpringMVC相結(jié)合實現(xiàn)文件上傳、下載功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-06-06Mybatis?連接mysql數(shù)據(jù)庫底層運行的原理分析
這篇文章主要介紹了Mybatis?連接mysql數(shù)據(jù)庫底層運行的原理分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03Java并發(fā)volatile可見性的驗證實現(xiàn)
這篇文章主要介紹了Java并發(fā)volatile可見性的驗證實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05