本篇文章為大家展示了synchronized的特性有哪些,代碼簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比潤州網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式潤州網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋潤州地區(qū)。費(fèi)用合理售后完善,十年實體公司更值得信賴。
1. synchronized鎖重入
1.1 介紹
關(guān)鍵字synchronized擁有鎖重入的功能,也就是在使用synchronized時,當(dāng)一個線程得到一個對象鎖后,再次請求此對象鎖時是可以再次得到該對象的鎖的。這說明在一個synchronized方法/塊內(nèi)部調(diào)用本類的其他synchronized方法/塊時,是永遠(yuǎn)可以得到鎖的。
例如:
public class Service1 { public synchronized void method1(){ System.out.println("method1"); method2(); } public synchronized void method2(){ System.out.println("method2"); method3(); } public synchronized void method3(){ System.out.println("method3"); } }
public class MyThread extends Thread { @Override public void run(){ Service1 service1 = new Service1(); service1.method1(); } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } }
運(yùn)行結(jié)果如下:
? 看到這個結(jié)果的時候是茫然了,怎么就證明是可重入鎖的了呢?
? “可重入鎖”的概念是:自己可以再次獲取自己的內(nèi)部鎖,比如有1個線程獲得了某個對象的鎖,此時這個對象鎖還沒有釋放,當(dāng)其再次想要獲取這個對象的鎖的時候還是可以獲取的,如果不可鎖重入的話,就會造成死鎖。
? “可重入鎖”的最大作用就是避免死鎖
1.2 分析
我們知道,在程序中,是無法顯式釋放對同步監(jiān)視器的鎖的,而會在如下幾個情況下釋放鎖:
① 當(dāng)前線程的同步方法、代碼塊執(zhí)行結(jié)束的時候釋放
② 當(dāng)前線程在同步方法、同步代碼塊遇到break、return終止該代碼塊或方法的時候釋放
③ 出現(xiàn)未處理的error或exception導(dǎo)致異常結(jié)束的時候釋放
④ 程序執(zhí)行了同步對象wait方法,當(dāng)前線程暫停,釋放鎖
那么,在上面的程序中,當(dāng)線程進(jìn)入同步方法method1時獲得Service1的對象鎖,但是在執(zhí)行method1的時候調(diào)用了同步方法method2,按照正常情況,在執(zhí)行同步方法method2同樣需要獲得對象鎖,但是根據(jù)上面釋放鎖的條件,此時method1的對象鎖還沒有釋放,此時就會造成死鎖,無法繼續(xù)執(zhí)行method2。但是通過上面代碼的執(zhí)行結(jié)果來看,能夠正常執(zhí)行method2和method3,這就說明,在一個Synchronized修飾的方法或代碼塊的內(nèi)部調(diào)用本類的其他Synchronized修飾的方法或代碼塊時,是永遠(yuǎn)可以得到鎖的。
1.3 父子可繼承性
可重入鎖支持在父子類繼承的環(huán)境中,示例代碼如下:
public class Service2 { public int i = 10; public synchronized void mainMethod(){ i--; System.out.println("main print i="+i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class Service3 extends Service2 { public synchronized void subMethod(){ try{ while (i>0){ i--; System.out.println("sub print i= "+i); Thread.sleep(100); this.mainMethod(); } }catch (InterruptedException e){ e.printStackTrace(); } } }
public class MyThread extends Thread { @Override public void run(){ Service3 service3 = new Service3(); service3.subMethod(); } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } }
運(yùn)行結(jié)果如下:
此程序說明,當(dāng)存在父子類繼承關(guān)系時,子類完全可以通過“可重入鎖”調(diào)用父類的同步方法。
2. 出現(xiàn)異常,鎖自動釋放
當(dāng)一個線程執(zhí)行的代碼出現(xiàn)異常時,其所持有的鎖會自動釋放。
驗證代碼如下:
public class Service4 { public synchronized void testMethod(){ if(Thread.currentThread().getName().equals("a")){ System.out.println("ThreadName= "+Thread.currentThread().getName()+" run beginTime="+System.currentTimeMillis()); int i=1; while (i == 1){ if((""+Math.random()).substring(0,8).equals("0.123456")){ System.out.println("ThreadName= "+Thread.currentThread().getName()+" run exceptionTime="+System.currentTimeMillis()); //Integer.parseInt("a"); } } }else{ System.out.println("Thread B run time= "+System.currentTimeMillis()); } } }
public class ThreadA extends Thread{ private Service4 service4; public ThreadA(Service4 service4){ this.service4 = service4; } @Override public void run(){ service4.testMethod(); } }
public class ThreadB extends Thread{ private Service4 service4; public ThreadB(Service4 service4){ this.service4 = service4; } @Override public void run(){ service4.testMethod(); } }
public class Main { public static void main(String[] args) { try { Service4 service4 = new Service4(); ThreadA a = new ThreadA(service4); a.setName("a"); a.start(); Thread.sleep(500); ThreadB b = new ThreadB(service4); b.setName("b"); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
注意Service4類中Integer.parseInt(“a”);此時處于被注釋狀態(tài),運(yùn)行結(jié)果如下:
由于a線程沒有錯誤,while(true),此時a線程處于無限循環(huán)狀態(tài),鎖一直被a占用,b線程無法獲得鎖,即無法執(zhí)行b線程。
將Service4類中Integer.parseInt(“a”);解開注釋,執(zhí)行的結(jié)果如下:
當(dāng)a線程發(fā)生錯誤時,b線程獲得鎖從而執(zhí)行,由此可見,當(dāng)方法出現(xiàn)異常時,鎖自動釋放。
3. 將任意對象作為監(jiān)視器
java支持對“任意對象”作為“對象監(jiān)視器”來實現(xiàn)同步的功能。這個“任意對象”大多數(shù)是實例變量及方法的參數(shù),使用格式為synchronized(非this對象x)同步代碼塊。
示例代碼如下:
public class StringLock { private String lock = "lock"; public void method(){ synchronized (lock){ try { System.out.println("當(dāng)前線程: "+Thread.currentThread().getName() + "開始"); Thread.sleep(1000); System.out.println("當(dāng)前線程: "+Thread.currentThread().getName() + "結(jié)束"); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final StringLock stringLock = new StringLock(); new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t1").start(); new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t2").start(); } }
運(yùn)行結(jié)果如下:
鎖非this對象具有一定的優(yōu)點:如果在一個類中有很多個synchronized方法,這時雖然能實現(xiàn)同步,但會受到阻塞,所以影響運(yùn)行效率;但如果使用同步代碼塊鎖非this對象,則synchronized(非this)代碼塊中的程序與同步方法是異步的,不予其他鎖this同步方法爭搶this鎖,則可大大提高運(yùn)行效率。
4. 同步不具有繼承性
父類的同步方法,在子類中重寫后不加同步關(guān)鍵字,是不會同步的,所以還得在子類的方法中添加synchronized關(guān)鍵字。
上述內(nèi)容就是synchronized的特性有哪些,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
本文題目:synchronized的特性有哪些
轉(zhuǎn)載來源:http://chinadenli.net/article38/pehjsp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、App設(shè)計、小程序開發(fā)、電子商務(wù)、微信公眾號、品牌網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)