1. 程式人生 > >多線程 synchronized關鍵字

多線程 synchronized關鍵字

sta 出現 col java out read 控制 stat 影響

在多線程情況下,當多個線程操作同一個資源的時候,會出現安全問題,例如臟讀(一個線程咋讀取變量的時候,值已經被另一個線程改變)。

synchronized關鍵字:可用來同步方法或者代碼塊。有關synchronized,總結一下幾條。

  1 synchronized關鍵字鎖的是對象,當多個對象會創建多個鎖,而達不到同步的效果。

  2 只有操作公共資源的時候才需要上鎖,非公共資源沒必要上鎖。

  3 synchronized關鍵字擁有可重入鎖。

  4 異常出現的時候,會自動釋放鎖。

  5 同步不具備繼承性。

  6 sleep()方法不會釋放鎖。

  7wait()方法會釋放鎖。

  8 synchronized可同步方法,也可以同步代碼塊。

下面對其中幾條進行驗證;

方法類:

public class MyMethod {

	
	synchronized public void methodA(String username) throws InterruptedException{
		System.out.println(username);
		if(username.equals("a")){
			
			System.out.println(Thread.currentThread().getName()+"  into methodA");
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getName()+"  out methodA");
		}
		else {
			System.out.println(Thread.currentThread().getName()+"  into methodB");
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName()+"  out methodB");
		}
		/*while(true){
			
		}*/
	}
	//synchronized 鎖代碼塊
	public static void methodB(String lock) throws InterruptedException{
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName()+"  into lock");
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName()+"  out lock");
			
		}
	}
}

  

主線程:synchronized同步代碼塊。synchronized(this)鎖的是當前對象。

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodB(lock);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodB(lock);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制臺:

t2  into lock
t2  out lock
t1  into lock
t1  out lock

  synchronized同步方法,修改主線程如下

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("a");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("b");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制臺輸出:

b
t2  into methodB
t2  out methodB
a
t1  into methodA
t1  out methodA

  可以發現達到同步的效果。

再次修改主線程代碼如下:

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("a");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m2.methodA("b");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制臺如下

b
a
t1  into methodA
t2  into methodB
t2  out methodB
t1  out methodA

  並且多次執行main方法,發現控制臺打印順序不同。此處調用的是兩個對象,所以jvm會創建兩個鎖,互不影響,所以在鎖,只能鎖一個對象中的方法。證明synchronized鎖的是對象。此過程中,我還測試了靜態方法,當把methodA()方法改為靜態的時候

兩個對象一樣會有同步的效果。

可重入鎖概念:自己可以再次獲取自己的內部鎖。如有一個線程獲得了某個對象的鎖,此時這個對象還沒有釋放,當其再次想獲取這個對象的鎖的時候,還是可以獲取的,否則會造成死鎖。

  

  每一個優秀的人,都有一段沈默的時光。不抱怨,不訴苦,最後度過那段感動自己的日子。

多線程 synchronized關鍵字