1. 程式人生 > >JAVA多執行緒安全之建構函式

JAVA多執行緒安全之建構函式

在一般情況下,Java的建構函式總結如下:

  1. 在建構函式一開始,this就是可用的了。 
  2. 建構函式和普通函式一樣,並不是預設被synchronized 的,有可能出現同步問題。 
  3. 如果建構函式中訪問靜態變數的話,必須同步這個靜態變數,否則一定會出問題。 
  4. 如果只訪問成員變數的話,無論在任何執行緒中,每一次建構函式被呼叫,其中的成員變數都是新建造出來的,因此不可能出現說在這個執行緒中執行的建構函式 會訪問到另一個執行緒中執行的建構函式中的成員變數的情況,因此這就是我所說的“訪問成員變數不可能出現同步問題”的意思。 這裡的前提是,兩個執行緒中都執行的是建構函式,而不是其他方法(例如start所啟動的run方法。)。 
  5. 如果在建構函式中,把this交給其他的執行緒去訪問,則其他執行緒可能在this例項還未初始化完畢時就訪問了其中的變數,這有可能產生同步問題。這時需要顯式同步this物件。

構造方法不需要同步化,因為它只可能發生在一個執行緒裡,在構造方法返回值前沒有其他執行緒可以使用該物件。(一個執行緒已經在構造方法裡面了,另外一個執行緒也可以呼叫構造方法,第一個執行緒裡面生成的物件和第二個執行緒裡面生成的物件是不同的物件。)

構造方法裡面使用的靜態屬性,是需要同步的,構造方法不執行完成其他執行緒是沒有辦法訪問該物件的,但是類物件是已經存在的,可以被多個執行緒訪問:如

public class Test {
	public static int id=0;
	public int c;
	public Test() {
		c=id;
		System.out.println(Thread.currentThread().getName() + "到達");
		try{
			Thread.sleep(100);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		id++;
	}
	public static void main(String [] args){
		class ThreadTst extends Thread {
			public void run(){
				Test test=new Test();
				System.out.println(test.c);
			}
		}
		new ThreadTst().start();
		new ThreadTst().start();
	}
}/* output
Thread-0到達
Thread-1到達
0
0
*/
public class Test {
	public static int id=0;
	public int c;
	public Test() {
		synchronized(Test.class) {
			c=id;
			System.out.println(Thread.currentThread().getName() + "到達");
			try{
				Thread.sleep(100);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
			id++;
		}
	}
	public static void main(String [] args){
		class ThreadTst extends Thread {
			public void run(){
				Test test=new Test();
				System.out.println(test.c);
			}
		}
		new ThreadTst().start();
		new ThreadTst().start();
	}
}
/* output
Thread-0到達
0
Thread-1到達
1
 */

子類可以置換掉父類的同步方法,使它同步或不同步。這就是說,子類的方法不繼承其父類方法的特性。父類的方法不改變,如果明顯地呼叫父類的同步方法,那麼這個將是同步呼叫的。

如果在建構函式中,把this交給其他的執行緒去訪問,則其他執行緒可能在this例項還未初始化完畢時就訪問了其中的變數,這有可能產生同步問題。這時需要顯式同步this物件。

class A {
	int i;

	public A () {
		synchronized(this) {
			new Snippet(this);
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			i = 2;
		}
	}
}

public class Snippet extends Thread {
	A a;

	public Snippet(A a) {
		this.a = a;
		start();
	}

	public void run() {
		synchronized(a) {
			System.out.println(a.i);
		}
	}

	public static void main(String[] args) {
		new A();
	}    
}
/* Output:
2
 *///:~