synchronized的作用
一、同步方法
public synchronized void methodAAA(){
//….
}
鎖定的是調用這個同步方法的對象
測試:
a、不使用這個關鍵字修飾方法,兩個線程調用同一個對象的這個方法。
目標類:



2



3



4

5

6

7

線程類:



2

3



4

5

6



7

8

9

調用:

2

3

4

5

6

結果:
輸出的數字交錯在一起。說明不是同步的,兩個方法在不同的線程中是異步調用的。
b、修改目標類,增加synchronized修飾



2



3



4

5

6

7

結果:
輸出的數字是有序的,首先輸出A的數字,然后是B,說明是同步的,雖然是不同的線程,但兩個方法是同步調用的。
注意:上面雖然是兩個不同的線程,但是是同一個實例對象。下面使用不同的實例對象進行測試。
c、每個線程都有獨立的TestThread對象。
目標類:



2



3



4

5

6

7

線程類:



2



3

4

5

6

7

調用:

2

3

4

5

結果:
輸出的數字交錯在一起。說明雖然增加了synchronized 關鍵字來修飾方法,但是不同的線程調用各自的對象實例,兩個方法仍然是異步的。
引申:
對于這種多個實例,要想實現同步即輸出的數字是有序并且按線程先后順序輸出,我們可以增加一個靜態變量,對它進行加鎖(后面將說明鎖定的對象)。
修改目標類:



2

3



4



5



6

7

8

9

10

二、同步代碼塊



2

3

4

5

鎖定一個對象,其實鎖定的是該對象的引用(object reference)
誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以按上面的代碼寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變量(它必須是一個對象)來充當鎖(上面的解決方法就是增加了一個狀態鎖)。
a、鎖定一個對象,它不是靜態的
private byte[] lock = new byte[0]; // 特殊的instance變量
目標類:



2

3



4



5

6

7



8

9

10

11

12

其實上面鎖定一個方法,等同于下面的:



2



3



4

5

6

7

b、鎖定一個對象或方法,它是靜態的
這樣鎖定,它鎖定的是對象所屬的類
public synchronized static void execute(){
//...
}
等同于



2



3



4


5

6

7

測試:
目標類:



2

3



4



5

6

7

8



9



10

11

12

13



14

15

16

17

線程類:調用不同的方法,于是建立了兩個線程類



2



3

4

5

6



7



8

9

10

11

調用:

2

3

4

5

6

注意:
1、用synchronized 來鎖定一個對象的時候,如果這個對象在鎖定代碼段中被修改了,則這個鎖也就消失了??聪旅娴膶嵗?/p>
目標類:



2



3

4



5

6

7



8

9

10

11

12

13



14

15

16

17



18

19

20



21



22

23

24

25



26



27

28

29

30



31

32

33

34

35

36

37



38



39

40

41

42

43

說明:在reload和checkValid方法中都增加了synchronized關鍵字,對lock對象進行加鎖。在不同線程中對同一個對象實例分別調用reload和checkValid方法。
在reload方法中,不修改lock對象即注釋lock="abc"; ,結果在控制臺輸出reload end后才輸出100。說明是同步調用的。
如果在reload方法中修改lock對象即去掉注釋,結果首先輸出了一個數字(當前ve的大小),然后輸出reload end。說明是異步調用的。
2、單例模式中對多線程的考慮



2



3

4



5

6

7



8

9

10

11

12



13

14

15

16



17

18

19

20

說明:增加了一個內部類,在內部類中申明一個靜態的對象,實例化該單例類,初始化的數據都在單例類的構造函數中進行。這樣保證了多個實例同時訪問的時候,初始化的數據都已經成功初始化了。
總結:
A. 無論synchronized關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作鎖,所以首先應知道需要加鎖的對象
B.每個對象只有一個鎖(lock)與之相關聯。
C.實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
呵呵,你把100改成1000試試
http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html
http://www.javaeye.com/topic/48750