對Java同步一些理解
kingfish 2005
------------------------------------------------------------
基本概念:
每個Object都會有1個鎖.
同步就是串行使用一些資源.
(說明:以下有些例子為了突出重點,省略了不必要的代碼.特別是省掉了一些成員變量,就是需要同步的對象.)
1. 多線程中對共享、可變的數據進行同步.
對于函數中的局部變量沒必要進行同步.
對于不可變數據,也沒必要進行同步.
多線程中訪問共享可變數據才有必要.
2. 單個線程中可以使用synchronized,而且可以嵌套,但無意義.
class Test {
public static void main(String[] args) {
Test t = new Test();
synchronized(t) {
synchronized(t) {
System.out.println("ok!");
}
}
}
}
3. 對象實例的鎖
class Test{
public synchronized void f1(){
//do something here
}
public void f2(){
synchronized(this){
//do something here
}
}
}
上面的f1()和f2()效果一致, synchronized取得的鎖都是Test某個實列(this)的鎖.
比如: Test t = new Test();
線程A調用t.f2()時, 線程B無法進入t.f1(),直到t.f2()結束.
作用: 多線程中訪問Test的同一個實例的同步方法時會進行同步.
4. class的鎖
class Test{
final static Object o= new Object();
public static synchronized void f1(){
//do something here
}
public static void f2(){
synchronized(Test.class){
//do something here
}
}
public static void f3(){
try {
synchronized (Class.forName("Test")) {
//do something here
}
}
catch (ClassNotFoundException ex) {
}
}
public static void g(){
synchronized(o){
//do something here
}
}
}
上面f1(),f2(),f3(),g()效果一致
f1(),f2(),f3()中synchronized取得的鎖都是Test.class的鎖.
g()是自己產生一個對象o,利用o的鎖做同步
作用: 多線程中訪問此類或此類任一個實例的同步方法時都會同步. singleton模式lazily initializing屬于此類.
5. static method
class Test{
private static int v = 0;
public static void f1(){
//do something, 但函數中沒用用到v
}
public synchronized static void f2(){
//do something, 函數中對v進行了讀/寫.
}
}
多線程中使用Test的某個實列時,
(1) f1()是線程安全的,不需要同步
(2) f2()這個靜態方法中使用了函數外靜態變量,所以需要同步.
6. 對線程的run()進行同步沒有意義,如 public synchronized void run()
class Test extends Thread{
public synchronized void run(){
while(true){
//do something
}
}
public synchronized void f(){
//...
}
}
這種例子會有一個問題, 執行run()時(內部在循環), 外部無法執行f()
class Test extends Thread{
public synchronized void run(){
//do something
}
}
這種例子同步基本沒用, 因為run()通常靠 new Test().start()來執行的.
因為Test實例不同,鎖也不同.