多線程 synchronized關鍵字
阿新 • • 發佈:2018-08-02
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關鍵字