各位看官,抓緊上車,老司機要接著飙車了。
<!------------------------------我是萬惡的分割線----------------------------------->
上回咱們講到多線程中有個不得不提的關鍵字---synchronized,不知道各位看官中有沒有對這句話表示費解的(沒有的話,咱們就委屈一下,假裝有),java的關鍵字有很多,多線程的關鍵字也不少,那為什麼會說synchronized是多線程中不得不提的關鍵字呢?各位看官不要著急,備好瓜子,且聽我細細道來。
話說當年java初現,天地法則新立,各種不足(ps:有不足就對了,沒有漏洞的話那還讓人活不活了),宇宙間那家伙是一片混亂。因為制度的不完善,導致各種行為得不到約束,java這位新君麾下的多線程,I/O等大將更是桀骜不馴,放縱手下無法無天,,,,啥,你問有多瘋狂?據說當初多線程的這個“多”代表2個以上的數時,效率低就不說了,各個線程的數據傳輸也會極其混亂,我嚴重懷疑牛頭馬面就是早期多線程的“傑出作品”。就在這人神共憤的關鍵時刻,天空一聲巨響,synchronized這個小將化好了妝,踏著七彩祥雲就登上了歷史的舞台。
上回分解時,不知各位看官還有印象沒有,我說過synchronized的作用相當於一個督察,在它的監督下,所有的線程,沒錯,是所有的,都必須按照先後順序一個個來,,,,啥?你媳婦要生了?你要回去看兒子?那你也得排隊,還有,不准有性別歧視,女孩你就不看了?,,,,,啥?你隔壁的二狗的第三只狗一窩生了40只狗,你要去道喜?那你也得排隊
不過,規矩是死的,人是活的,不讓插隊,那多排幾隊,大家同時進行。啪(ps:腦補一下,驚堂木一聲驚堂),正主來了,今天小子就給大家說道說道synchronized的同步方法(敲黑板)。
上回說到線程安全分為“線程安全”和“非線程安全”,我這有一個祖傳的傳男不傳女,傳內不傳外的秘密,偷偷告訴大家,大家別往外傳,“非線程安全”問題存在於“實例變量”中,如果是方法內的私有變量,則不存在“非線程安全”,也就是俗說的業內黑話---“線程安全”了;如果多個線程同時訪問1個對象中的實例變量,那就有可能出現“非線程安全”問題,此外,如果多線程訪問的對象中如果有多個實例變量,則運行的結果又可能出現交叉的情況,我嚴重懷疑牛頭馬面就是這麼出來的(ps:純屬逗樂,都別當真哈)。
實例如下(如果巧合,看來成功的路都是一樣的,:)):
首先,創建一個HasSelfPrivateNum類
1 public class HasSelfPrivateNum 2 { 3 public void addI(String userName) 4 { 5 try 6 { 7 int num = 0; 8 if(userName.equals("a")) 9 { 10 num = 100; 11 System.out.println("a set over"); 12 Thread.sleep(100); 13 } 14 else 15 { 16 num = 200; 17 System.out.println("b set over"); 18 } 19 System.out.println(userName+" num="+num); 20 } 21 catch(InterruptedException e) 22 { 23 e.printStackTrace(); 24 } 25 } 26 }
創建一個ThreadA類:
1 public class ThreadA extends Thread 2 { 3 private HasSelfPrivateNum numRef; 4 public ThreadA(HasSelfPrivateNum numRef) 5 { 6 super(); 7 this.numRef=numRef; 8 } 9 public void run() 10 { 11 super.run(); 12 numRef.addI("a"); 13 } 14 }
創建一個ThreadB類:
public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef=numRef; } public void run() { super.run(); numRef.addI("b"); } }
下面是Run類:
1 public class Run 2 { 3 public static void main(String[] args) 4 { 5 HasSelfPrivateNum numRef = new HasSelfPrivateNum(); 6 ThreadA n = new ThreadA(numRef); 7 n.start(); 8 ThreadB m = new ThreadB(numRef); 9 m.start(); 10 } 11 }
好了,咱們跑一下試試:
試驗結果很明顯,由於沒用synchronized,即兩個線程訪問一個沒有同步的方法,出現了”非線程安全“。下面,我們對程序做一個個微整形,在HasSelfPrivateNum類的public void addI(String userName)方法前添加關鍵字--synchronized,
1 public class HasSelfPrivateNum 2 { 3 synchronized public void addI(String userName) 4 { 5 try 6 { 7 int num = 0; 8 if(userName.equals("a")) 9 { 10 num = 100; 11 System.out.println("a set over"); 12 Thread.sleep(100); 13 } 14 else 15 { 16 num = 200; 17 System.out.println("b set over"); 18 } 19 System.out.println(userName+" num="+num); 20 } 21 catch(InterruptedException e) 22 { 23 e.printStackTrace(); 24 } 25 } 26 }
我們再跑一次:
這次試驗我們可以看出,由於是同步訪問,所以結果是先打印a,然後打印出b.
結論:在兩個線程訪問同一個對象中的同步方法時,一定是線程安全的。
<!---------------------我是萬惡的分割線,我又來了------------->
啪,精彩不斷,好戲連連,預知後事如何,且聽下回分解。
啪,未完待續。
啪,明天見。