張孝祥_Java多線程與併發庫高級應用02

03. 傳統線程互斥技術

       線程安全問題例子:銀行轉賬

       同一個賬戶一邊進行出賬操作(自己交學費),另一邊進行入賬操作(別人給自己付款),線程不同步帶來的安全問題

示例:逐個字符的方式打印字符串

class Outputer

{

       public void output(String name)

       {

       int len =name.length();

       for (int i=0; i<len; i++)

              SOP(name.charAt(i));逐個字符打印

       SOP();換行

}

}

public void test()

{

       Outputeroutputer = new Outputer();

       newThread(

new Runnable()

{

       public void run()

       {

              Thread.sleep(100);

       outputer.output(“zhangxiaoxiang”);

}

}).start();

       newThread(

new Runnable()

{

       public void run()

       {

              Thread.sleep(100);

       outputer.output(“lihuoming”);

}

}).start();

}

注意:

內部類不能訪問局部變量,要訪問需加final

靜態方法中不能創建內部類的實例對象

打印結果發現的問題:線程不同步所致,兩個線程都在使用同一個對象

要避免下邊產生的問題,左邊方法體中的代碼要實現原子性

有一個線程正在使用這個方法的代碼,別的線程就不能再使用。

就和廁所裏的坑一樣,已經有人在用了,別人就不能再去用了。

Java中某段代碼要實現排他性,就將這段代碼用synchronized關鍵字保護起來。

同步鎖可以用任意對象,相當於門鎖

synchronizedname

{

for (int i=0; i<len; i++)

       SOP(name.charAt(i));逐個字符打印

       SOP();換行

}

這樣的話,有一個線程進入保護區域後,沒出來的話,別的線程就不能進入保護區域。


互斥方法:

       a、同步代碼塊

              synchronized(lock){}

       b、同步方法

              方法返回值前加synchronized

              同步方法上邊用的鎖就是this對象

              靜態同步方法使用的鎖是該方法所在的class文件對象

使用synchronized關鍵字實現互斥,要保證同步的地方使用的是同一個鎖對象

       public synchronized void output(String name)

       {

       int len =name.length();

       這裏就不要再加同步了,加上極易出現死鎖

       for (int i=0; i<len; i++)

              SOP(name.charAt(i));逐個字符打印

       SOP();換行

}

 

04. 傳統線程同步通信技術

       面試題,子線程10次與主線程100次來回循環執行50次

       下面是我剛看完面試題就暫停視頻自己試着寫的代碼,還可以,結果完成要求了

在單次循環結束後讓這個剛結束循環的線程休眠,保證另一個線程可以搶到執行權。

public class ThreadInterViewTest

{

       /**

        * 剛看到面試題沒看答案之前試寫

        * 子線程循環10次,回主線程循環100次,

        * 再到子線程循環10次,再回主線程循環100次

        * 如此循環50次     

        */

       publicstatic void main(String[] args)

       {

              intnum = 0;

              while(num++<50)

              {

                     newThread(new Runnable()

                                   {

                                          @Override

                                          public void run()

                                          {

                                                 circle("子線程運行", 10);

                                          }

                                   }).start();

                     try

                     {

                            //加這句是保證上邊的子線程先運行,剛開始沒加,主線程就先開了

                            Thread.sleep(2000);

                     }catch (InterruptedException e)

                     {

                            e.printStackTrace();

                     }

                     circle("主線程", 100);  

              }

       }

      

       publicstatic synchronized void circle(String name, int count)

       {

              for(int i=1; i<=count; i++)

              {

                     System.out.println(name+"::"+i);

              }

              try

              {

                     Thread.sleep(5000);

              }catch (InterruptedException e)

              {

                     e.printStackTrace();

              }

       }

}

 

張老師講的方法:

1、將子線程和主線程中要同步的方法進行封裝,加上同步關鍵字實現同步

2、兩個線程間隔運行,添加一個標記變量進行比較以實現相互通信,加色的部分

wait   notify  notifyAll  wait會拋出異常

class Business

{

       private boolean bShouleSub = true;

       publicsynchronized void sub()

       {

              if (bShouleSub)

              {

                     for (int i=1; i<11; i++)

                     SOP(sub+i);

              bShouldSub= false;

              this.notify();

}

else

       this.wait();

}

       publicsynchronized void main()

       {

              if (!bShouldSub)

              {

                     for (int i=1; i<101; i++)

                     SOP(main+i);

              bShouldSub= true;

              this.notify();

}

else

       this.wait();

}

}

經驗:要用到共同數據(包括同步鎖)或相同算法的多個方法要封裝在一個類中

       鎖是上在代表要操作的資源類的內部方法中的,而不是上在線程代碼中的。這樣寫出來的類就是天然同步的,只要使用的是同一個new出來的對象,那麼這個對象就具有同步互斥特性

       判斷喚醒等待標記時使用while增加程序健壯性,防止僞喚醒

此處使用while以增加程序健壯性,因爲存在虛假喚醒,有時候並沒有被notify就醒了。如果該方法沒有同步的話,此處就更要使用while進行判斷了,避免進程不同步問題


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章