各位看官,抓緊上車,老司機要接著飙車了。
<!------------------------------我是萬惡的分割線----------------------------------->
上回咱們講到多線程中有個不得不提的關鍵字---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.
結論:在兩個線程訪問同一個對象中的同步方法時,一定是線程安全的。
<!---------------------我是萬惡的分割線,我又來了------------->
啪,精彩不斷,好戲連連,預知後事如何,且聽下回分解。
啪,未完待續。
啪,明天見。