第一個例子是同一實(shí)例方法加鎖和不加鎖在多線程情況下的訪問情況,代碼如下:
package test.caipiao.log;
/**
* 一個類的同一個實(shí)例,方法加鎖和不加鎖情況下的訪問情況.
* @author lfl
*
*/
public class Test {
public static void main(String[] args) {
final TT tt = new TT();
Thread t1 = new Thread() {
public void run() {
tt.test(); //調(diào)用加鎖的test()
}
};
Thread t2 = new Thread() {
public void run() {
tt.test2(); //調(diào)用加鎖的test2()
}
};
Thread t3 = new Thread() {
public void run() {
tt.test3(); //調(diào)用不加鎖的test3()
}
};
/**
* t1 t2 t3 三個線程依次啟動運(yùn)行.
*/
t1.start();
t2.start();
t3.start();
System.out.println("over");
}
}
class TT {
public synchronized void test() {
for (int i = 0; i < 10000000; i++) {
if (i % 10000 == 0) {
System.out.println(i +"---");
}
}
}
public synchronized void test2() {
System.out.println("test2");
}
public void test3() {
System.out.println("test3");
}
}
輸出如下(多次運(yùn)行和不同計(jì)算機(jī)上運(yùn)行輸出結(jié)果可能不一樣):
over 0 --- test3 10000 --- 20000 --- 30000 --- 40000 --- 50000 --- 60000 ---
......
9910000 --- 9920000 --- 9930000 --- 9940000 --- 9950000 --- 9960000 --- 9970000 --- 9980000 --- 9990000 --- test2
說明:
主線程先輸出 over,主線程沒有持有tt上的鎖,這里就不關(guān)心了。
t1線程輸出0,此時還在持有tt上的鎖,t3線程就輸出test3,說明線程t1持有tt上的鎖,而不影響t3線程調(diào)用test3()方法,即允許其它線程方法訪問該實(shí)例的非加鎖方法。而最后輸出test2,是在線程t1釋放了tt上的鎖后
線程t3獲得tt上的鎖才能調(diào)用test2()方法,即一個線程持有當(dāng)前實(shí)例的鎖,其它線程不能訪問該實(shí)例的加鎖方法。
-------------------------------分割線-------------------------------------------------
第二個例子是靜態(tài)方法加鎖和不加鎖在多線程情況下的訪問情況,代碼如下:
package test.caipiao.log;
/**
* 一個類的同一個實(shí)例,方法加鎖和不加鎖情況下的訪問情況.
* @author lfl
*
*/
public class TestStatic {
public static void main(String[] args) {
final TTStatic tt = new TTStatic();
Thread t1 = new Thread() {
public void run() {
TTStatic.test(); //調(diào)用加鎖的test()
}
};
Thread t2 = new Thread() {
public void run() {
TTStatic.test2(); //或者
tt.test2(); //調(diào)用加鎖的test2()
}
};
Thread t3 = new Thread() {
public void run() {
TTStatic.test3(); //調(diào)用不加鎖的test3()
}
};
/**
* t1 t2 t3 三個線程依次啟動運(yùn)行.
*/
t1.start();
t2.start();
t3.start();
System.out.println("over");
}
}
class TTStatic {
public static synchronized void test() {
for (int i = 0; i < 10000000; i++) {
if (i % 10000 == 0) {
System.out.println(i +"---");
}
}
}
public static synchronized void test2() {
System.out.println("test2");
}
public static void test3() {
System.out.println("test3");
}
}
輸出如下(多次運(yùn)行和不同計(jì)算機(jī)上運(yùn)行輸出結(jié)果可能不一樣):
0 ---
10000 ---
20000 ---
30000 ---
40000 ---
50000 ---
60000 ---
70000 ---
80000 ---
90000 ---
test3
over
100000 ---
110000 ---
120000 ---
130000 ---
......
9920000 ---
9930000 ---
9940000 ---
9950000 ---
9960000 ---
9970000 ---
9980000 ---
9990000 ---
test2
test2
說明:
基本同第一個例子的分析一樣,只不過這里線程持有的是TTStatic class對象上的鎖,而TTStatic class對象只有一個。需要說明的是最后輸出的兩個test2,這個說明調(diào)用靜態(tài)的加鎖方法,不論是用類名調(diào)用還是實(shí)例調(diào)用,都需要獲得該類的class對象上的鎖。
-------------------------------------------分割線------------------------------------------------------
第三個例子是同一實(shí)例方法加鎖和不加鎖在多線程情況下和靜態(tài)方法加鎖和不加鎖在多線程情況下的訪問情況,代碼如下:
package test.caipiao.log;
/**
* 一個類的同一個實(shí)例,方法加鎖和不加鎖情況下的訪問情況.
* @author lfl
*
*/
public class TestHybrid {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
TTHybrid.test(); //調(diào)用加鎖的test()
}
};
Thread t2 = new Thread() {
public void run() {
TTHybrid.test2(); //調(diào)用加鎖的test2()
}
};
Thread t3 = new Thread() {
public void run() {
TTHybrid.test3(); //調(diào)用不加鎖的test3()
}
};
//下面是非靜態(tài)方法調(diào)用
final TTHybrid tt = new TTHybrid();
Thread t4 = new Thread() {
public void run() {
tt.test4(); //調(diào)用加鎖的test4()
}
};
Thread t5 = new Thread() {
public void run() {
tt.test5(); //調(diào)用加鎖的test5()
}
};
Thread t6 = new Thread() {
public void run() {
tt.test6(); //調(diào)用不加鎖的test6()
}
};
/**
* t1 t2 t3 三個線程依次啟動運(yùn)行.
*/
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
System.out.println("over");
}
}
class TTHybrid {
public static synchronized void test() {
for (int i = 0; i < 10000000; i++) {
if (i % 10000 == 0) {
System.out.println(i +"--- static");
}
}
}
public static synchronized void test2() {
System.out.println("test2");
}
public static void test3() {
System.out.println("test3");
}
public synchronized void test4() {
for (int i = 0; i < 10000000; i++) {
if (i % 10000 == 0) {
System.out.println(i +"--- instance");
}
}
}
public synchronized void test5() {
System.out.println("test5");
}
public void test6() {
System.out.println("test6");
}
}
輸出如下(多次運(yùn)行和不同計(jì)算機(jī)上運(yùn)行輸出結(jié)果可能不一樣):
0 --- static
over
test3
0 --- instance
10000 --- static
10000 --- instance
20000 --- instance
30000 --- instance
20000 --- static
40000 --- instance
50000 --- instance
30000 --- static
60000 --- instance
40000 --- static
50000 --- static
60000 --- static
70000 --- instance
test6
90000 --- static
100000 --- instance
100000 --- static
110000 --- static
120000 --- static
110000 --- instance
130000 --- static
120000 --- instance
140000 --- static
130000 --- instance
150000 --- static
......
9960000 --- instance
9370000 --- static
9970000 --- instance
9380000 --- static
9980000 --- instance
9390000 --- static
9990000 --- instance
9400000 --- static
9410000 --- static
test5
9420000 --- static
9430000 --- static
......
9970000 --- static
9980000 --- static
9990000 --- static
test2
說明:
主線程輸出的over,t3線程輸出的test3和t6線程輸出的test6,可以看到無論是否是靜態(tài)的,持有相應(yīng)的鎖對該類方法的訪問沒有影響。接著可以看到test()和test4()方法,基本是交替調(diào)用輸出的,這說明持有TTHybrid class 對象上的鎖和持有tt上的鎖是沒有直接關(guān)系的,即持有TTHybrid class 對象上的鎖訪問靜態(tài)方法不會影響持有tt上的鎖訪問非靜態(tài)方法。test4()輸出完畢后釋放tt上的鎖 后,test5()方法開始輸出。test()輸出完畢后釋放TTHybrid class 對象上的鎖 后,test2()方法開始輸出。
通過這三個小例子應(yīng)該對Java中實(shí)例方法和靜態(tài)方法在多線程下加鎖和不加鎖的訪問情況有了一定的了解。關(guān)于synchronized關(guān)鍵字的具體含義請參看其它相關(guān)資料。