指標(biāo)
理解synchronized的含義、明確synchronized關(guān)鍵字修飾普通方法、靜態(tài)方法和代碼塊時鎖對象的差異。
問題
- 有一個類叫A,里面包含一個synchronized修飾的普通方法缘屹,方法名print;創(chuàng)建兩個A的實例,在兩個線程中并發(fā)訪問print方法侠仇,能否構(gòu)成線程同步轻姿?
- 將print方法添加static修飾呢?
synchronized關(guān)鍵字修飾普通方法
先定義了一個A的類傅瞻,里面有個synchronized修飾的print方法踢代,print方法打印一個數(shù)字,這個數(shù)字每調(diào)用一次就加1. 代碼如下:
public class A {
private static final String TAG = "A";
public synchronized void print(){
Log.d(TAG, "print: " + Data.getCounter());
}
}
public final class Data {
private static int counter = 0;
public static int getCounter(){
counter ++;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
return counter;
}
}
接下來驗證,創(chuàng)建2個A對象嗅骄,分別在各自的線程中循環(huán)10次調(diào)用print方法
final A a = new A();
final A a1 = new A();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10;i ++){
a.print();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10;i ++){
a1.print();
}
}
}).start();
日志如下:
11-14 11:27:20.118 26130-26144/com.example.administrator.myapplication2 D/A: print: 2
11-14 11:27:20.118 26130-26145/com.example.administrator.myapplication2 D/A: print: 3
11-14 11:27:20.138 26130-26144/com.example.administrator.myapplication2 D/A: print: 4
11-14 11:27:20.138 26130-26145/com.example.administrator.myapplication2 D/A: print: 5
11-14 11:27:20.158 26130-26144/com.example.administrator.myapplication2 D/A: print: 6
11-14 11:27:20.158 26130-26145/com.example.administrator.myapplication2 D/A: print: 7
11-14 11:27:20.178 26130-26144/com.example.administrator.myapplication2 D/A: print: 8
11-14 11:27:20.179 26130-26145/com.example.administrator.myapplication2 D/A: print: 9
11-14 11:27:20.199 26130-26144/com.example.administrator.myapplication2 D/A: print: 10
11-14 11:27:20.199 26130-26145/com.example.administrator.myapplication2 D/A: print: 10
11-14 11:27:20.219 26130-26144/com.example.administrator.myapplication2 D/A: print: 12
11-14 11:27:20.219 26130-26145/com.example.administrator.myapplication2 D/A: print: 12
...
上面的日志只是其中一次運行結(jié)果胳挎,線程調(diào)度每次都可能不同,會呈現(xiàn)不同的結(jié)果溺森。但每一次運行幾乎都會有重復(fù)的數(shù)字出現(xiàn)慕爬,說明并沒有構(gòu)成線程的同步。如果線程同步日志
的數(shù)字應(yīng)該是依次加1屏积。
synchronized關(guān)鍵字修飾靜態(tài)方法
把上面A類的print方法添加static医窿,再運行多次,日志里數(shù)字始終依次加1炊林,說明是線程間是同步的
synchronized關(guān)鍵字在代碼塊時
把print修改成如下:
public void print(){
synchronized (this){
Log.d(TAG, "print: " + Data.getCounter());
}
}
運行結(jié)果跟synchronized關(guān)鍵字修飾普通方法時一致姥卢,線程不同步。
再把print修改成如下:
public void print(){
synchronized (A.class){
Log.d(TAG, "print: " + Data.getCounter());
}
}
運行結(jié)果跟synchronized關(guān)鍵字修飾靜態(tài)方法時一致渣聚,線程同步独榴。
結(jié)論
Java是一門面向?qū)ο缶幊陶Z言,萬物皆對象奕枝,synchronized里的鎖絕逼也是對象棺榔。
- 在synchronized關(guān)鍵字在代碼塊的例子中,第一種情況的鎖是this, 不同A的實例隘道,this固然不同症歇,所以兩者的鎖是不同的;
第二種情況的鎖是A.class郎笆, 一個A類只有一個class實例,所以始終都是同一把鎖; - synchronized關(guān)鍵字修飾普通方法忘晤,只是隱藏鎖宛蚓, 鎖還是this
- synchronized關(guān)鍵字修飾靜態(tài)方法, 也是隱藏鎖, 鎖是A.class