java中synchronized Lock(本地同步)鎖的8種情況
Lock(本地同步)鎖的8種情況總結與說明:
* 題目:
* 1.標準訪問,請問是先打印郵件還是短信 Email
* 2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信 Email
* 3.新增普通的hello方法,請問先打印郵件還是hello hello
* 4.兩部手機,請問先打印郵件還是短信 SMS
* 5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信 Email
* 6.兩個靜態同步方法,2部手機,請問先打印郵件還是短信 Email
* 7.一個普通同步方法,一個靜態同步方法,1部手機,請問先打印郵件還是短信 SMS
* 8.一個普通同步方法,一個靜態同步方法,2部手機,請問先打印郵件還是短信 SMS
*
* lock1、2
* 一個對象裡面如果有多個synchronized方法,某一時刻內,隻要一個線程去調用其中的一個synchronized方法,
* 其他的線程都隻能等待,換句話說,某一時刻內,隻能有唯一一個線程去訪問這些synchronized方法,
* 鎖的是當前對象的this,被鎖定後,其它的線程都不能進入到當前對象的其它的synchronized方法
*
* lock3、4
* 加個普通的方法後和同步鎖無關
* 換成兩個對象後,不是同一把鎖瞭,情況立刻變化
*
* lock5、6
* 都換成靜態同步方法後,情況又變化(靜態鎖的是Class類對象)
* 若是普通同步方法,new this,具體的一部一部手機,所有的普通同步方法用的都是同一把鎖—-示例對象本身
* 若是靜態同步方法,static class,唯一的一個模板
* synchronized是實現同步的基礎:Java中的每一個對象都可以作為鎖
* 具體表現為一下3種形式。
* 對於普通同步方法,鎖是當前實例對象。它等同於 對於同步方法塊,鎖是synchronized括號裡的配置的對象。
* 對於靜態同步方法,鎖是當前類的Class類元信息
*
* lock7、8
* 當一個線程試圖訪問同步代碼塊時它首先必須得到鎖,退出或拋出異常時必須釋放鎖
*
* 所有的同步方法用的都是同一把鎖—-實例對象本身,就是new出來的具體實例對象本身
* 也就是說如果一個實例對象的普通同步方法獲取鎖後,該實例對象的其他普通同步方法必須等待獲取鎖的方法釋放鎖後才能獲得鎖
* 可是別的實例對象的普通同步方法因為跟該實例對象的普通同步方法用到是不同鎖,所以不用等待該實例對象已獲取鎖的普通
* 同步方法釋放鎖就可以獲取它們自己的鎖
*
* 所有的靜態同步方法用的也是同一把鎖—-類對象本身,就是我們說過的唯一模板Class
* 具體實例對象this和唯一模板Class,這兩把鎖是兩個不同的對象,所有靜態同步方法與普通同步方法之間是不會有競態條件的,
* 但是一旦一個靜態同方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖。
lock1、2、3一個實例對象
lock4、5、6、7、8兩個實例對象
lock1
1.標準訪問,請問是先打印郵件還是短信?答案:Email
sendEmail()與sendSms()都是普通同步方法,都使用synchronized鎖
這裡按方法調用順序,依次執行,當前synchronized鎖住的是同一個實例對象
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public synchronized void sendEmail() throws InterruptedException{ System.out.println("------------sendEmail"); } public synchronized void sendSms(){ System.out.println("------------sendSMS"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信 Email */ public class Lock8{ public static void main(String[] args) throws InterruptedException{ Phone phone=new Phone(); //線程A發送Email new Thread(()->{ try{ phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); //線程B發送短信 newThread(()->{ phone.sendSms(); },"B").start(); } }
lock2
2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信? 答案:Email
lock2是lock1的變形,其原理與lock1一致,synchronized鎖住的是同一個對象,必須等到第一個方法把鎖釋放後,第二個方法才能夠獲得鎖
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public synchronized void sendEmail()throwsInterruptedException{ //睡眠4秒種 TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } public synchronized void sendSms(){ System.out.println("------------sendSMS"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email */ public class Lock8{ public static void main(String[] args)throws InterruptedException{ //資源類 Phone phone=new Phone(); //線程A sendEmail newThread(()->{ try{ phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); //這裡保證線程A能夠執行完 Thread.sleep(300); //線程B sendSms newThread(()->{ phone.sendSms(); },"B").start(); } }
結果:等待4秒中後出現sendEmail與sendSMS同時輸出
lock3
3.新增普通的hello方法,請問先打印郵件還是hello? 答案:hello
隻有添加synchronized關鍵字的方法才會被synchronized鎖控制
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public synchronized void sendEmail()throws InterruptedException{ TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } public synchronized void sendSms(){ System.out.println("------------sendSMS"); } public void hello(){//未加synchronized System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hello hello */ public class Lock8{ public static void main(String[] args)throws InterruptedException{ Phone phone=new Phone(); //線程A調用sendEmail new Thread(()->{ try{ phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); //線程B調用普通方法hello new Thread(()->{ //phone.sendSms(); phone.hello(); },"B").start(); } }
結果:hello先輸出,4s後sendEmail再輸出
lock4
4.兩部手機,請問先打印郵件還是短信 ? 答案:SMS
不同實例對象,synchronized鎖住的是對應的調用對象
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public synchronized void sendEmail()throws InterruptedException{ //睡眠4秒種 TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } public synchronized void sendSms(){ System.out.println("------------sendSMS"); } public void hello(){ System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hellohello *4.兩部手機,請問先打印郵件還是短信 SMS */ public class Lock8{ public static void main(String[] args)throws InterruptedException{ Phone phone=new Phone(); Phone phone2=new Phone(); //sychronized鎖定是當前對象對應的this,phone與phone2分別鎖的是自己的this //線程A使用實例phone調用sendEmail newThread(()->{ try{ //sendEmail方法中包含睡眠4秒種 phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); //線程B使用實例phone2調用sendSms newThread(()->{ phone2.sendSms(); //phone.hello(); },"B").start(); } }
結果:sendSMS先輸出,4s後sendEmail再輸出
lock5
5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信? 答案:Email
synchronized鎖靜態方法,實際是鎖住的類元信息,因為靜態方法是隨類元信息的加載而保存到jvm的靜態區,是所有實例創建的模板
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public static synchronized void sendEmail()throws InterruptedException{ TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } public static synchronized void sendSms(){ System.out.println("------------sendSMS"); } public void hello(){ System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hellohello *4.兩部手機,請問先打印郵件還是短信SMS *5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信 Email */ public class Lock8{ public static void main(String[] args)throws InterruptedException{ Phone phone=new Phone(); new Thread(()->{ try{ phone.sendEmail(); }catch(InterruptedException e){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); newThread(()->{ phone.sendSms(); },"B").start(); } }
結果:4秒種後,sendEmail率先輸出,sendSMS緊隨其後
lock6
6.兩個靜態同步方法,2部手機,請問先打印郵件還是短信? 答案:Email
與lock5的運行結果一致,當前synchronized鎖住的是類元信息
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public static synchronized void sendEmail() throws InterruptedException{ TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } public static synchronized void sendSms(){ System.out.println("------------sendSMS"); } public void hello(){ System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hellohello *4.兩部手機,請問先打印郵件還是短信SMS *5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信Email *6.兩個靜態同步方法,2部手機,請問先打印郵件還是短信Email */ public class Lock8{ publicstaticvoidmain(String[]args)throwsInterruptedException{ Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try{ phone.sendEmail(); }catch(InterruptedException e){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); new Thread(()->{ //phone.sendSms(); phone2.sendSms(); //phone.hello(); },"B").start(); } }
結果:與lock5的運行結果一致,sendEmail與sendSMS都是4s後進行輸出,synchronized也是鎖住的類元信息
lock7
7.一個普通同步方法,一個靜態同步方法,1部手機,請問先打印Email還是SMS? 答案:SMS
原理:普通同步方法,synchronized鎖住的是當前實例對象,當前實例對象存在於jvm的堆內存區
靜態同步方法,synchronized鎖住的是當前類的類元信息,存在於jvm元空間的靜態區中
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ //靜態同步方法 public static synchronized void sendEmail()throws InterruptedException{ TimeUnit.SECONDS.sleep(4); System.out.println("------------sendEmail"); } //普通同步方法 public synchronized void sendSms(){//無static System.out.println("------------sendSMS"); } public void hello(){ System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hellohello *4.兩部手機,請問先打印郵件還是短信SMS *5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信Email *6.兩個靜態同步方法,2部手機,請問先打印郵件還是短信Email *7.一個普通同步方法,一個靜態同步方法,1部手機,請問先打印郵件還是短信 SMS */ public class Lock8{ public static void main(String[] args) throws InterruptedException{ Phonephone=newPhone(); Phonephone2=newPhone(); newThread(()->{ try{ phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); newThread(()->{ phone.sendSms(); //phone2.sendSms(); //phone.hello(); },"B").start(); } }
結果:sendSMS先輸出,4s後sendEmail再輸出
lock8
8.一個普通同步方法,一個靜態同步方法,2部手機,請問先打印郵件還是短信? 答案:SMS
原理:與lock7一致
package day02_lam; import java.util.concurrent.TimeUnit; class Phone{ public static synchronized void sendEmail()throwsInterruptedException{ TimeUnit.SECONDS.sleep(3); System.out.println("------------sendEmail"); } public synchronized void sendSms(){ System.out.println("------------sendSMS"); } public void hello(){ System.out.println("hello"); } } /** *題目: *1.標準訪問,請問是先打印郵件還是短信Email *2.email方法新增暫停4秒鐘,請問是先打印郵件還是短信Email *3.新增普通的hello方法,請問先打印郵件還是hellohello *4.兩部手機,請問先打印郵件還是短信SMS *5.兩個靜態同步方法,1部手機,請問先打印郵件還是短信Email *6.兩個靜態同步方法,2部手機,請問先打印郵件還是短信Email *7.一個普通同步方法,一個靜態同步方法,1部手機,請問先打印郵件還是短信SMS *8.一個普通同步方法,一個靜態同步方法,2部手機,請問先打印郵件還是短信SMS */ public class Lock8{ publicstaticvoidmain(String[]args)throwsInterruptedException{ Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try{ phone.sendEmail(); }catch(InterruptedExceptione){ e.printStackTrace(); } },"A").start(); Thread.sleep(300); new Thread(()->{ //phone.sendSms(); phone2.sendSms(); //phone.hello(); },"B").start(); } }
結果:運行結果與lock7一致,sendSMS先輸出,4s後sendEmail再輸出
到此這篇關於java中synchronized Lock(本地同步)鎖的8種情況的文章就介紹到這瞭,更多相關 synchronized Lock鎖內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 新手初學Java網絡編程
- 淺談Java鎖的膨脹過程以及一致性哈希對鎖膨脹的影響
- 淺談synchronized加鎖this和class的區別
- 淺談Java並發中ReentrantLock鎖應該怎麼用
- 5個步驟讓你明白多線程和線程安全