<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【185期】面試官:你能說說 Synchronized實現(xiàn)對象鎖的兩種方式以及它的原理嗎?

          共 4851字,需瀏覽 10分鐘

           ·

          2021-04-28 19:37

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
          關(guān)注


          閱讀本文大概需要 4.5 分鐘。

          來自:blog.csdn.net/x541211190/article/details/106179245

          一.同步代碼塊鎖

          案例:通過同步代碼塊鎖,實現(xiàn)兩個線程對同一個全局變量count,各自執(zhí)行1萬次count++,驗證結(jié)果是否等于2萬,而不會出現(xiàn)小于2萬的情況。
          完整代碼實現(xiàn):

          public class SynchronizeCodeBlockLock implements Runnable {
           private static SynchronizeCodeBlockLock instance = new SynchronizeCodeBlockLock();
           private static int count = 0;

           @Override
           public void run() {
            method();
           }

           private void method() {
            // 關(guān)鍵:同步代碼塊的方式,操作同一變量,達到線程安全的效果
            synchronized (this) {
             System.out.println("線程名:" + Thread.currentThread().getName() + ",運行開始");
             for (int i = 0; i < 10000; i++) {
              count++;
             }
             System.out.println("線程:" + Thread.currentThread().getName() + ",運行結(jié)束");
            }
           }

           public static void main(String[] args) {
            Thread thread1 = new Thread(instance);
            Thread thread2 = new Thread(instance);
            thread1.start();
            thread2.start();
            while (thread1.isAlive() || thread2.isAlive()) {
             // 若有線程如果還在活動,則不執(zhí)行下一步(等同于thread.join()方法)
            }
            System.out.println("期待結(jié)果:20000,實際結(jié)果:" + count);
           }


          }

          運行結(jié)果:

          線程名:Thread-0,運行開始
          線程:Thread-0,運行結(jié)束
          線程名:Thread-1,運行開始
          線程:Thread-1,運行結(jié)束
          期待結(jié)果:20000,實際結(jié)果:20000

          分析運行結(jié)果:
          我們發(fā)現(xiàn)使用了synchronized關(guān)鍵字后,線程Thread-0先執(zhí)行,等到其結(jié)束后,Thread-1才開始執(zhí)行。如果不使用synchronized關(guān)鍵字,執(zhí)行結(jié)果可能會是Thread-0和Thread-1幾乎同時執(zhí)行,幾乎同時運行結(jié)束。這就說明使用了synchronized關(guān)鍵字后,將多個線程的并行,變?yōu)榱舜小?/section>

          二.方法鎖

          本例僅展示方法鎖,在控制線程串行執(zhí)行的示例。方法鎖保證線程安全的效果,跟同步代碼塊是一致的。

          public class MethodLock implements Runnable {

           private static MethodLock instance = new MethodLock();

           @Override
           public void run() {
            method();
           }

           //關(guān)鍵:synchronized可以保證此方法被順序執(zhí)行,線程1執(zhí)行完4秒鐘后,線程2再執(zhí)行4秒。不加synchronized,線程1和線程2將同時執(zhí)行
           private synchronized void method() {
            System.out.println("線程:" + Thread.currentThread().getName() + ",運行開始");
            try {
             //模擬執(zhí)行一段操作,耗時4秒鐘
             Thread.sleep(4000);
             System.out.println("線程:" + Thread.currentThread().getName() + ",運行結(jié)束");
            } catch (InterruptedException e) {
             e.printStackTrace();
            }
           }

           public static void main(String[] args) {
            // 模擬:同一個對象下,兩個線程,同步執(zhí)行一個方法(串行執(zhí)行則為線程安全,并行執(zhí)行,則為線程不安全,)
            Thread thread1 = new Thread(instance);
            Thread thread2 = new Thread(instance);
            thread1.start();
            thread2.start();
            while (thread1.isAlive() || thread2.isAlive()) {

            }
            System.out.println("測試結(jié)束");
           }
          }

          運行結(jié)果:

          線程:Thread-0,運行開始
          線程:Thread-0,運行結(jié)束
          線程:Thread-1,運行開始
          線程:Thread-1,運行結(jié)束
          測試結(jié)束

          發(fā)現(xiàn)運行結(jié)果中,多個線程也是串行執(zhí)行的,效果跟同步代碼塊鎖是一致的。

          三.synchronized關(guān)鍵字,是怎么保證線程安全的呢?

          在Java中所有的對象,都會有一把鎖,叫做內(nèi)置鎖,也稱作監(jiān)視器鎖。這是種排他鎖。
          排他鎖:一個線程獲取后,其他線程只能等待其釋放后,才有機會獲得該鎖。
          Java中每個對象,都可以把內(nèi)置鎖,當做一個同步鎖來使用。當一個線程在進入到synchronized代碼塊前時,會自動獲取到監(jiān)視器鎖,此時其他線程在訪問synchronized代碼塊時,就會被堵塞掛起(被拒之門外的意思)。拿到鎖的線程會在執(zhí)行完成、或者拋出異常、或者調(diào)用wait系列方法時釋放該鎖。其他線程只能等待鎖被釋放后才能獲取該鎖。
          通俗的講,synchronized關(guān)鍵字將代碼塊中代碼由并行轉(zhuǎn)變成了串行,這樣就保證了代碼被順序執(zhí)行。

          四.synchronized在內(nèi)存層面,是如何實現(xiàn)加鎖和釋放鎖的?

          • 進入synchronized代碼塊時,會將代碼塊內(nèi)用到的變量從該線程的工作內(nèi)存中清除,轉(zhuǎn)而從主內(nèi)存中獲取。

          • 退出synchronized代碼塊時,會將代碼塊內(nèi)用到的變量的修改,刷新到主內(nèi)存中。

          這其實就是synchronized解決共享變量內(nèi)存可見性的原理。關(guān)于synchronized的性質(zhì)(可見性、可重入性),我會在后續(xù)其他文章中詳細解釋。

          五.synchronized將線程的并行處理轉(zhuǎn)為串行處理,有什么缺點?

          synchronized將并行改為串行,當然會影響程序的執(zhí)行效率,執(zhí)行速度會受到影響。其次,synchronized操作線程的堵塞,也就是由操作系統(tǒng)控制CPU的內(nèi)核進行上下文的切換,這個切換本身也是耗時的。所以使用synchronized關(guān)鍵字會降低程序的運行效率。

          六. 使用Synchronized關(guān)鍵字需要注意什么?

          1.Synchronized使用時需要注意的地方鎖對象不能為空。
          鎖對象的信息是保留在對象頭中的,如果對象為空,則鎖的信息也就不存在了。
          2.作用域不宜過大
          synchronized代碼塊的代碼量不宜過多,如果把過多的代碼放在其中,程序的運行會變?yōu)榇校俣葧陆怠8鱾€線程并行可以提高效率,我們應(yīng)該僅把那些影響線程安全的代碼,放入synchronized代碼塊中,串行執(zhí)行;不需要考慮線程安全的代碼,并行執(zhí)行,達到效率最高。
          3.避免死鎖
          避免讓線程對鎖持有并等待的情況出現(xiàn)(后續(xù)文章將講解死鎖的相關(guān)知識)。

          七.總結(jié)

          本文講解了Java中的對象鎖的兩種實現(xiàn)方式,分別是以下兩種實現(xiàn)形式:
          方式一:同步代碼塊鎖:

          synchronized (共享變量) {
              //需要同步的代碼
          }

          方式二:方法鎖:

           private synchronized void method() {
               //需要同步的代碼
           }

          無論你使用哪一種形式,都應(yīng)該在保證同步的情況下,盡量減少同步代碼的內(nèi)容,這樣可以提高程序的運行效率,還能保證線程的安全。
          <END>

          推薦閱讀:

          【184期】SQL數(shù)據(jù)庫面試題以及答案(50例題)

          【182期】SpringCloud常見面試題(2020最新版)

          【181期】HashMap 面試二十一問!

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公眾號內(nèi)回復(fù)「2048」,即可免費獲取!!

          微信掃描二維碼,關(guān)注我的公眾號

          朕已閱 

          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃在线一区二区三区精品 | 日韩欧美精品 | 搞黄色的在线观看 | 国产成人AV无码一区二区三区 | 青青草视频分类在线 |