免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      面了一個(gè)25歲的學(xué)妹,把synchronized關(guān)鍵字講的那叫一個(gè)透徹

      面了一個(gè)25歲的學(xué)妹,把synchronized關(guān)鍵字講的那叫一個(gè)透徹

      二哥:“三妹,以前都是我講你聽,今天我們換個(gè)形式,假裝我是面試官,你來講講 synchronized 關(guān)鍵字的應(yīng)用方式和內(nèi)存語義吧。”

      三妹(顏值在線,氣質(zhì)也在線):“我們這是要互換角色嗎?哈哈哈哈。”

      前言

      “好吧,來吧?!比靡稽c(diǎn)也不怯場(chǎng)。

      在 Java 中,關(guān)鍵字 synchronized 可以保證在同一個(gè)時(shí)刻,只有一個(gè)線程可以執(zhí)行某個(gè)方法或者某個(gè)代碼塊(主要是對(duì)方法或者代碼塊中存在共享數(shù)據(jù)的操作),同時(shí)我們還應(yīng)該注意到 synchronized 另外一個(gè)重要的作用,synchronized 可保證一個(gè)線程的變化(主要是共享數(shù)據(jù)的變化)被其他線程所看到(保證可見性,完全可以替代 Volatile 功能)。

      synchronized 的三種應(yīng)用方式

      synchronized 關(guān)鍵字最主要有以下 3 種應(yīng)用方式,下面分別介紹:

      • 修飾實(shí)例方法,作用于當(dāng)前實(shí)例加鎖,進(jìn)入同步代碼前要獲得當(dāng)前實(shí)例的鎖;
      • 修飾靜態(tài)方法,作用于當(dāng)前類對(duì)象加鎖,進(jìn)入同步代碼前要獲得當(dāng)前類對(duì)象的鎖;
      • 修飾代碼塊,指定加鎖對(duì)象,對(duì)給定對(duì)象加鎖,進(jìn)入同步代碼庫前要獲得給定對(duì)象的鎖。

      synchronized 作用于實(shí)例方法

      所謂的實(shí)例對(duì)象鎖就是用 synchronized 修飾實(shí)例對(duì)象中的實(shí)例方法,注意是實(shí)例方法不包括靜態(tài)方法,如下:

      public class AccountingSync implements Runnable { //共享資源(臨界資源) static int i = 0; // synchronized 修飾實(shí)例方法 public synchronized void increase() { i ++; } @Override public void run() { for(int j=0;j<1000000;j++){ increase(); } } public static void main(String args[]) throws InterruptedException { AccountingSync instance = new AccountingSync(); Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("static, i output:" + i); }}/** * 輸出結(jié)果: * static, i output:2000000 */

      如果在函數(shù) increase()前不加 synchronized,因?yàn)?i++不具備原子性,所以最終結(jié)果會(huì)小于 2000000,具體分析可以參考文章《Java 并發(fā)編程系列 2-volatile》。下面這點(diǎn)非常重要:

      一個(gè)對(duì)象只有一把鎖,當(dāng)一個(gè)線程獲取了該對(duì)象的鎖之后,其他線程無法獲取該對(duì)象的鎖,所以無法訪問該對(duì)象的其他 synchronized 實(shí)例方法,但是其他線程還是可以訪問該實(shí)例對(duì)象的其他非 synchronized 方法。

      但是一個(gè)線程 A 需要訪問實(shí)例對(duì)象 obj1 的 synchronized 方法 f1(當(dāng)前對(duì)象鎖是 obj1),另一個(gè)線程 B 需要訪問實(shí)例對(duì)象 obj2 的 synchronized 方法 f2(當(dāng)前對(duì)象鎖是 obj2),這樣是允許的:

      public class AccountingSyncBad implements Runnable { //共享資源(臨界資源) static int i = 0; // synchronized 修飾實(shí)例方法 public synchronized void increase() { i ++; } @Override public void run() { for(int j=0;j<1000000;j++){ increase(); } } public static void main(String args[]) throws InterruptedException { // new 兩個(gè)AccountingSync新實(shí)例 Thread t1 = new Thread(new AccountingSyncBad()); Thread t2 = new Thread(new AccountingSyncBad()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("static, i output:" + i); }}/** * 輸出結(jié)果: * static, i output:1224617 */

      上述代碼與前面不同的是我們同時(shí)創(chuàng)建了兩個(gè)新實(shí)例 AccountingSyncBad,然后啟動(dòng)兩個(gè)不同的線程對(duì)共享變量 i 進(jìn)行操作,但很遺憾操作結(jié)果是 1224617 而不是期望結(jié)果 2000000,因?yàn)樯鲜龃a犯了嚴(yán)重的錯(cuò)誤,雖然我們使用 synchronized 修飾了 increase 方法,但卻 new 了兩個(gè)不同的實(shí)例對(duì)象,這也就意味著存在著兩個(gè)不同的實(shí)例對(duì)象鎖,因此 t1 和 t2 都會(huì)進(jìn)入各自的對(duì)象鎖,也就是說 t1 和 t2 線程使用的是不同的鎖,因此線程安全是無法保證的。

      每個(gè)對(duì)象都有一個(gè)對(duì)象鎖,不同的對(duì)象,他們的鎖不會(huì)互相影響。

      解決這種困境的的方式是將 synchronized 作用于靜態(tài)的 increase 方法,這樣的話,對(duì)象鎖就當(dāng)前類對(duì)象,由于無論創(chuàng)建多少個(gè)實(shí)例對(duì)象,但對(duì)于的類對(duì)象擁有只有一個(gè),所有在這樣的情況下對(duì)象鎖就是唯一的。下面我們看看如何使用將 synchronized 作用于靜態(tài)的 increase 方法。

      synchronized 作用于靜態(tài)方法

      當(dāng) synchronized 作用于靜態(tài)方法時(shí),其鎖就是當(dāng)前類的 class 鎖,不屬于某個(gè)對(duì)象。

      當(dāng)前類 class 鎖被獲取,不影響對(duì)象鎖的獲取,兩者互不影響。

      由于靜態(tài)成員不專屬于任何一個(gè)實(shí)例對(duì)象,是類成員,因此通過 class 對(duì)象鎖可以控制靜態(tài)成員的并發(fā)操作。需要注意的是如果一個(gè)線程 A 調(diào)用一個(gè)實(shí)例對(duì)象的非 static synchronized 方法,而線程 B 需要調(diào)用這個(gè)實(shí)例對(duì)象所屬類的靜態(tài) synchronized 方法,不會(huì)發(fā)生互斥現(xiàn)象,因?yàn)樵L問靜態(tài) synchronized 方法占用的鎖是當(dāng)前類的 class 對(duì)象,而訪問非靜態(tài) synchronized 方法占用的鎖是當(dāng)前實(shí)例對(duì)象鎖,看如下代碼:

      public class AccountingSyncClass implements Runnable { static int i = 0; /** * 作用于靜態(tài)方法,鎖是當(dāng)前class對(duì)象,也就是 * AccountingSyncClass類對(duì)應(yīng)的class對(duì)象 */ public static synchronized void increase() { i++; } // 非靜態(tài),訪問時(shí)鎖不一樣不會(huì)發(fā)生互斥 public synchronized void increase4Obj() { i++; } @Override public void run() { for(int j=0;j<1000000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException { //new新實(shí)例 Thread t1=new Thread(new AccountingSyncClass()); //new新實(shí)例 Thread t2=new Thread(new AccountingSyncClass()); //啟動(dòng)線程 t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); }}/** * 輸出結(jié)果: * 2000000 */

      由于 synchronized 關(guān)鍵字修飾的是靜態(tài) increase 方法,與修飾實(shí)例方法不同的是,其鎖對(duì)象是當(dāng)前類的 class 對(duì)象。注意代碼中的 increase4Obj 方法是實(shí)例方法,其對(duì)象鎖是當(dāng)前實(shí)例對(duì)象,如果別的線程調(diào)用該方法,將不會(huì)產(chǎn)生互斥現(xiàn)象,畢竟鎖對(duì)象不同,但我們應(yīng)該意識(shí)到這種情況下可能會(huì)發(fā)現(xiàn)線程安全問題(操作了共享靜態(tài)變量 i)。

      synchronized 同步代碼塊

      在某些情況下,我們編寫的方法體可能比較大,同時(shí)存在一些比較耗時(shí)的操作,而需要同步的代碼又只有一小部分,如果直接對(duì)整個(gè)方法進(jìn)行同步操作,可能會(huì)得不償失,此時(shí)我們可以使用同步代碼塊的方式對(duì)需要同步的代碼進(jìn)行包裹,這樣就無需對(duì)整個(gè)方法進(jìn)行同步操作了,同步代碼塊的使用示例如下:

      public class AccountingSync2 implements Runnable { static AccountingSync2 instance = new AccountingSync2(); // 餓漢單例模式 static int i=0; @Override public void run() { //省略其他耗時(shí)操作…. //使用同步代碼塊對(duì)變量i進(jìn)行同步操作,鎖對(duì)象為instance synchronized(instance){ for(int j=0;j<1000000;j++){ i++; } } } public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); }}/** * 輸出結(jié)果: * 2000000 */

      從代碼看出,將 synchronized 作用于一個(gè)給定的實(shí)例對(duì)象 instance,即當(dāng)前實(shí)例對(duì)象就是鎖對(duì)象,每次當(dāng)線程進(jìn)入 synchronized 包裹的代碼塊時(shí)就會(huì)要求當(dāng)前線程持有 instance 實(shí)例對(duì)象鎖,如果當(dāng)前有其他線程正持有該對(duì)象鎖,那么新到的線程就必須等待,這樣也就保證了每次只有一個(gè)線程執(zhí)行 i++;操作。當(dāng)然除了 instance 作為對(duì)象外,我們還可以使用 this 對(duì)象(代表當(dāng)前實(shí)例)或者當(dāng)前類的 class 對(duì)象作為鎖,如下代碼:

      //this,當(dāng)前實(shí)例對(duì)象鎖synchronized(this){ for(int j=0;j<1000000;j++){ i++; }}//class對(duì)象鎖synchronized(AccountingSync.class){ for(int j=0;j<1000000;j++){ i++; }}

      synchronized 禁止指令重排分析

      指令重排的情況,可以參考文章《Java 并發(fā)編程系列 1-基礎(chǔ)知識(shí)》

      我們先看如下代碼:

      class MonitorExample { int a = 0; public synchronized void writer() { //1 a++; //2 } //3 public synchronized void reader() { //4 int i = a; //5 //…… } //6}

      假設(shè)線程 A 執(zhí)行 writer()方法,隨后線程 B 執(zhí)行 reader()方法。根據(jù) happens before 規(guī)則,這個(gè)過程包含的 happens before 關(guān)系可以分為兩類:

      • 根據(jù)程序次序規(guī)則,1 happens before 2, 2 happens before 3; 4 happens before 5, 5 happens before 6。
      • 根據(jù)監(jiān)視器鎖規(guī)則,3 happens before 4。
      • 根據(jù) happens before 的傳遞性,2 happens before 5。

      上述 happens before 關(guān)系的圖形化表現(xiàn)形式如下:

      在上圖中,每一個(gè)箭頭鏈接的兩個(gè)節(jié)點(diǎn),代表了一個(gè) happens before 關(guān)系。黑色箭頭表示程序順序規(guī)則;橙色箭頭表示監(jiān)視器鎖規(guī)則;藍(lán)色箭頭表示組合這些規(guī)則后提供的 happens before 保證。

      上圖表示在線程 A 釋放了鎖之后,隨后線程 B 獲取同一個(gè)鎖。在上圖中,2 happens before 5。因此,線程 A 在釋放鎖之前所有可見的共享變量,在線程 B 獲取同一個(gè)鎖之后,將立刻變得對(duì) B 線程可見。

      synchronized 的可重入性

      從互斥鎖的設(shè)計(jì)上來說,當(dāng)一個(gè)線程試圖操作一個(gè)由其他線程持有的對(duì)象鎖的臨界資源時(shí),將會(huì)處于阻塞狀態(tài),但當(dāng)一個(gè)線程再次請(qǐng)求自己持有對(duì)象鎖的臨界資源時(shí),這種情況屬于重入鎖,請(qǐng)求將會(huì)成功。

      synchronized 就是可重入鎖,因此一個(gè)線程調(diào)用 synchronized 方法的同時(shí),在其方法體內(nèi)部調(diào)用該對(duì)象另一個(gè) synchronized 方法是允許的,如下:

      public class AccountingSync implements Runnable{ static AccountingSync instance=new AccountingSync(); static int i=0; static int j=0; @Override public void run() { for(int j=0;j<1000000;j++){ //this,當(dāng)前實(shí)例對(duì)象鎖 synchronized(this){ i++; increase();//synchronized的可重入性 } } } public synchronized void increase(){ j++; } public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); }}

      當(dāng)前實(shí)例對(duì)象鎖后進(jìn)入 synchronized 代碼塊執(zhí)行同步代碼,并在代碼塊中調(diào)用了當(dāng)前實(shí)例對(duì)象的另外一個(gè) synchronized 方法,再次請(qǐng)求當(dāng)前實(shí)例鎖時(shí),將被允許。需要特別注意另外一種情況,當(dāng)子類繼承父類時(shí),子類也是可以通過可重入鎖調(diào)用父類的同步方法。注意由于 synchronized 是基于 monitor 實(shí)現(xiàn)的,因此每次重入,monitor 中的計(jì)數(shù)器仍會(huì)加 1。

      ending

      “三妹,今天就學(xué)到這吧?!蔽曳隽朔鲅坨R對(duì)三妹說。

      記住 synchronized 的三種應(yīng)用方式,指令重排情況分析,以及 synchronized 的可重入性,通過今天的學(xué)習(xí),你基本可以掌握 synchronized 的使用姿勢(shì),以及可能會(huì)遇到的坑。

      原文鏈接:https://mp.weixin.qq.com/s/q5QYVSgqtqNWijyp1hM-yQ

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月23日 06:11
      下一篇 2022年6月23日 06:11

      相關(guān)推薦

      • 分享4條發(fā)微商朋友圈的方法(微商朋友圈應(yīng)該怎么發(fā))

        對(duì)于微商朋友來說,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底該怎么發(fā)呢? 為什么同樣是經(jīng)營一個(gè)朋友圈,有的微商看起來逼格滿滿,實(shí)際效果也不錯(cuò);而有的卻動(dòng)都不動(dòng)就被屏蔽甚至拉黑…

        2022年11月27日
      • 《寶可夢(mèng)朱紫》夢(mèng)特性怎么獲得?隱藏特性獲取方法推薦

        寶可夢(mèng)朱紫里有很多寶可夢(mèng)都是擁有夢(mèng)特性會(huì)變強(qiáng)的寶可夢(mèng),很多玩家不知道夢(mèng)特性怎么獲得,下面就給大家?guī)韺毧蓧?mèng)朱紫隱藏特性獲取方法推薦,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 …

        2022年11月25日
      • 《寶可夢(mèng)朱紫》奇魯莉安怎么進(jìn)化?奇魯莉安進(jìn)化方法分享

        寶可夢(mèng)朱紫中的奇魯莉安要怎么進(jìn)化呢?很多玩家都不知道,下面就給大家?guī)韺毧蓧?mèng)朱紫奇魯莉安進(jìn)化方法分享,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 奇魯莉安進(jìn)化方法分享 奇魯莉安…

        2022年11月25日
      • 淘寶直播開通后帶貨鏈接怎么做(淘寶直播需要開通淘寶店鋪嗎)

        直播帶貨無論是對(duì)于商家來說還是主播收益都是非??捎^的,所以不少平臺(tái)都有直播帶貨功能,一些小伙伴也想加入淘寶直播,那么淘寶直播開通后帶貨鏈接怎么做?下面小編為大家?guī)硖詫氈辈ラ_通后帶…

        2022年11月24日
      • cpu性能天梯圖2022 AMD CPU天梯圖最新排行榜出爐

        用戶在DIY自己的主機(jī)時(shí)選擇CPU是非常關(guān)鍵的,CPU可以說是電腦的大腦,大家也都想追求好一點(diǎn)的CPU來使用,但型號(hào)太多了,大部分的用戶都不知道目前哪一款CPU比較好用,快來看看詳…

        2022年11月24日
      • 《寶可夢(mèng)朱紫》暴飛龍?jiān)趺醋ィ勘╋w龍獲得方法

        寶可夢(mèng)朱紫暴飛龍位置在哪?在游戲中,很多玩家還不清楚暴飛龍具體要怎么樣獲得,其實(shí)獲得方法很簡(jiǎn)單,暴飛龍直接是沒得抓的,需要玩家從寶貝龍進(jìn)化得到,下面一起來看一下寶可夢(mèng)朱紫暴飛龍獲得…

        2022年11月23日
      • 《寶可夢(mèng)朱紫》布土撥怎么進(jìn)化?布土撥進(jìn)化方法介紹

        寶可夢(mèng)朱紫中,不同的寶可夢(mèng)有不同的進(jìn)化方法,其中布土撥的進(jìn)化方法是比較特殊的。很多玩家不知道寶可夢(mèng)朱紫布土撥怎么進(jìn)化,下面就帶來寶可夢(mèng)朱紫布土撥進(jìn)化方法介紹,一起來看看吧,希望能幫…

        2022年11月23日
      • 《寶可夢(mèng)朱紫》薄荷怎么獲得?薄荷獲得方法

        寶可夢(mèng)朱紫中薄荷有改變寶可夢(mèng)的屬性或性格等效果,很多玩家想知道寶可夢(mèng)朱紫薄荷怎么獲得,下面就帶來寶可夢(mèng)朱紫薄荷獲得方法,感興趣的小伙伴一起來看看吧,希望能幫助到大家。 薄荷獲得方法…

        2022年11月23日
      • 《寶可夢(mèng)朱紫》怎么交換精靈?交換精靈方法一覽

        寶可夢(mèng)朱紫中玩家可以和好友或者npc進(jìn)行交換寶可夢(mèng)獲得自己沒有的寶可夢(mèng),很多玩家想知道寶可夢(mèng)朱紫怎么交換精靈,下面就帶來寶可夢(mèng)朱紫交換精靈方法一覽,感興趣的小伙伴不要錯(cuò)過,希望能幫…

        2022年11月23日
      • 《寶可夢(mèng)朱紫》龍爪技能怎么獲得?龍爪技能獲取方法

        寶可夢(mèng)朱紫龍爪技能怎么獲得?在游戲中,很多玩家還不清楚龍爪技能應(yīng)該怎么獲取,其實(shí)獲取方法有很多,下面一起來看一下寶可夢(mèng)朱紫龍爪技能獲取方法,希望可以幫助各位玩家順利的進(jìn)行游戲內(nèi)容。…

        2022年11月23日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息