<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # JAVA之旅(十四)——靜態同步函數的鎖是class對象,多線程的單例設計模式,死鎖,線程中的通訊以及通訊所帶來的安全隱患,等待喚醒機制 * * * > JAVA之旅,一路有你,加油! ## 一.靜態同步函數的鎖是class對象 > 我們在上節驗證了同步函數的鎖是this,但是對于靜態同步函數,你又知道多少呢? > > 我們做一個這樣的小實驗,我們給show方法加上static關鍵字去修飾 ~~~ private static synchronized void show() { if (tick > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread() + "show:" + tick--); } } ~~~ > 然后我們來打印一下 ![這里寫圖片描述](http://img.blog.csdn.net/20160605104517114) > 發現他打印出0票了,說明他還是存在this隱患,同時也說明了一點就是他使用的鎖不是this,那既然不是this,那是什么呢? * 因為靜態方法中,不可以定義this,我們可以分析,靜態進內存中,內存中沒有本類對象,但是一定有該類的字節碼文件對象類名.class,我們可以這樣同步 ~~~ synchronized (MyThread.class) ~~~ > 你就會發現,線程是安全的了 > > 靜態同步的方法,使用的鎖是該字節碼的對象 類名.class ## 二.多線成中的單例設計模式 > 還記得我們講的單例設計模式嗎?我們今年溫習一下這兩個實現單例模式的方法 ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 單例設計模式 */ } } /** * 餓漢式 * * @author LGL * */ class Single1 { private static final Single1 s = new Single1(); private Single1() { } public static Single1 getInstance() { return s; } } /** * 懶漢式 * @author LGL * */ class Single { private static Single s = null; private Single() { } public static Single getInstance() { if (s == null) { s = new Single(); } return s; } } ~~~ > 我們著重點來看懶漢式,你會發現這個s是共享數據,所以我們所以延遲訪問的話,一定會出現安全隱患的,但是我們使用synchronized來修飾的話,多線程啟動每次都要判斷有沒有鎖,勢必會麻煩的,所以我們可以這樣寫 ~~~ public static Single getInstance() { if (s == null) { synchronized (Single.class) { if (s == null) { s = new Single(); } } } return s; } ~~~ > 這樣其實是比較麻煩的,我們用餓漢式比較多,懶漢式作用是延時加載,多線成訪問就會有安全問題 ## 三.多線程的死鎖 > 我們同步當中會產生一個問題,那就是死鎖 * 同步中嵌套同步 > 是怎么個意思?我們來實現一下這段代碼 ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 需求:簡單的賣票程序,多個線程同時賣票 */ MyThread myThread = new MyThread(); Thread t1 = new Thread(myThread); Thread t2 = new Thread(myThread); t1.start(); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } myThread.flag = false; t2.start(); } } /** * 賣票程序 * * @author LGL * */ class MyThread implements Runnable { // 票數 private int tick = 100; Object j = new Object(); boolean flag = true; @Override public void run() { if (flag) { while (true) { synchronized (j) { show(); } } } else { while (true) { show(); } } } private synchronized void show() { synchronized (j) { if (tick > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread() + "show:" + tick--); } } } } ~~~ > 這段代碼里面,this鎖中又object鎖,object中又this鎖,就會導致死鎖,不信?我們運行一下 ![這里寫圖片描述](http://img.blog.csdn.net/20160605191725280) > 你會看到他會停止不動了,這就是死鎖,而在我們開發中,我們應該盡量避免死鎖的發生。 ## 四.線程中的通訊 > 線程中的通訊,是比較重要的,我們看一下這張例圖 ![這里寫圖片描述](http://img.blog.csdn.net/20160605192129097) > 存什么,取什么 > > 線程中通訊,其實就是多個線程在操作同一個資源,但是操作的動作不同。我們來具體看看例子 ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 線程間通訊 */ } } // 資源 class Res { String name; String sex; } // 輸入 class Input implements Runnable { @Override public void run() { } } // 輸出 class Output implements Runnable { @Override public void run() { } } ~~~ > 我們定義這些個類,對吧,一個資源,兩個操作,緊接著,我們應該怎么去操作他? ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 線程間通訊 */ Res s = new Res(); Input in = new Input(s); Output out = new Output(s); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } // 資源 class Res { String name; String sex; } // 輸入 class Input implements Runnable { private Res s; public Input(Res s) { this.s = s; } @Override public void run() { int x = 0; while (true) { if (x == 0) { s.name = "lgl"; s.sex = "男"; } else if (x == 1) { s.name = "zhangsan"; s.sex = "女"; } // 交替 x = (x + 1) % 2; } } } // 輸出 class Output implements Runnable { private Res s; public Output(Res s) { this.s = s; } @Override public void run() { while (true) { System.out.println(s.name + "..." + s.sex); } } } ~~~ > 這樣去操作,你看下輸出,這里出現了一個有意思的現象 ![這里寫圖片描述](http://img.blog.csdn.net/20160606203343552) > 你回發現他輸出的竟然有女,這就是存在了安全隱患,但是也進一步的證實了,線程間的通訊 ## 五.線程通訊帶來的安全隱患 > 我們線程通訊,會有安全隱患,那已經怎么去解決呢?我們是不是一來就想到了同步synchronized?其實這樣做沒用的, 因為你傳的鎖是不一樣的,你要想讓鎖唯一,就類名.class ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 線程間通訊 */ Res s = new Res(); Input in = new Input(s); Output out = new Output(s); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } // 資源 class Res { String name; String sex; } // 輸入 class Input implements Runnable { private Res s; Object o = new Object(); public Input(Res s) { this.s = s; } @Override public void run() { int x = 0; while (true) { synchronized (Input.class) { if (x == 0) { s.name = "lgl"; s.sex = "男"; } else if (x == 1) { s.name = "zhangsan"; s.sex = "女"; } // 交替 x = (x + 1) % 2; } } } } // 輸出 class Output implements Runnable { private Res s; public Output(Res s) { this.s = s; } @Override public void run() { while (true) { synchronized (Input.class) { System.out.println(s.name + "..." + s.sex); } } } } ~~~ > 這樣,就解決了問題了 ## 六.多線程等待喚醒機制 > 我們不需要多線成高速消耗CPU,而是在適當的時候喚醒他,所以我們需要定義一個布爾值 ~~~ package com.lgl.hellojava; //公共的 類 類名 public class HelloJJAVA { public static void main(String[] args) { /** * 線程間通訊 */ Res s = new Res(); Input in = new Input(s); Output out = new Output(s); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } // 資源 class Res { String name; String sex; boolean flag = false; } // 輸入 class Input implements Runnable { private Res s; Object o = new Object(); public Input(Res s) { this.s = s; } @Override public void run() { int x = 0; while (true) { synchronized (Input.class) { if (s.flag) { try { // 等待線程都存放在線程池 wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (x == 0) { s.name = "lgl"; s.sex = "男"; } else if (x == 1) { s.name = "zhangsan"; s.sex = "女"; } // 交替 x = (x + 1) % 2; s.flag = true; // 通知 notify(); } } } } // 輸出 class Output implements Runnable { private Res s; public Output(Res s) { this.s = s; } @Override public void run() { while (true) { synchronized (Input.class) { if (!s.flag) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { System.out.println(s.name + "..." + s.sex); s.flag = false; notify(); } } } } } ~~~ > 都使用在同步中,因為要對待件監視器(鎖)的線程操作,所以要使用在線程中,因為只有同步才具有鎖 > > 為什么這些操作線程的方法要定義在Object類中呢?因為這些方法在操作同步線程中,都必須要標識它們所操作線程持有的鎖,只有同一個鎖上的被等待線程可以被同一個鎖上notify,不可以對不同鎖中的線程進行喚醒,也就是說,等待和喚醒必須是同一把鎖!而鎖可以是任意對象,所以可以被任意對象調用的方法定義在Object類中。 > > 我們今天介紹就先到這里,線程的概念比較多,我們要寫好幾篇!!! #### 如果有興趣,可以加群:555974449 版權聲明:本文為博主原創文章,博客地址:http://blog.csdn.net/qq_26787115,未經博主允許不得轉載。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看