相關免費學習推薦:java基礎教學
8鎖定問題示範
1.標準訪問
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
標準訪問,先列印郵件還是簡訊.
不一定誰先被列印。取決於CPU的執行情況.激活他們的是main線程,後面誰先被調度,不知道。
為了確保效果,我們在A和B的程式碼之間加thread.sleep(100)。此時,可以確保A先被列印。
解釋:
只要一個資源類別裡面,不管它有多少個同步方法,只要一個執行緒先存取了資源類別裡面的任何一個同步方法,那麼它鎖的不是這個方法,鎖的是該方法所在的整個資源類別。也就是說,鎖的是對象。它鎖的不是目前的方法。
也就是說,這些synchoronized的方法都屬於同一個資源類別裡面,而鎖的是整個資源類別。
2.在郵件方法中暫停4秒,請問先列印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
先列印郵件。同步方法取得的phone物件鎖定,sleep不會釋放鎖定。到了時間會立即執行。所以先列印郵件方法
解釋:
它與問題1類似。
只要一個資源類別裡面,不管它有多少個同步方法,只要一個執行緒先存取了資源類別裡面的任何一個同步方法,那麼它鎖的不是這個方法,鎖的是這個方法所在的整個資源類別。也就是說,鎖的是對象。它鎖的不是目前的方法。
舉個例子:我和班長要用同一個手機打電話,我一定要等班長打完電話才能接著打。班長用的過程中停網了一段時間,那我也只能等班長打完。
3.新增普通sayHello方法,請問先列印郵件還是hello
#先列印hello
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); phone.sayHello(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
#解釋:加上普通方法後發現和同步鎖定無關。因此它無需等待同步鎖釋放。
這裡可以舉個例子。班長用它的手機要打電話。而我要向班長借手機充電線,這兩個不互斥,因此可以在班長打電話完之前就借走充電線。
4.兩部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
解釋:這裡可以舉個例子,班長用它的手機法郵件。我用我自己的手機打電話。那麼誰先誰後就沒有關係。
5.兩個靜態同步方法,同一部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}解釋:可以跟問題6一起分析
6.兩個靜態同步方法,兩部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}## 解析: static屬於一個類別。也就說,他不屬於當前對象this的一個獨立的個體。而是屬於全域的class。這就要考慮物件鎖和全域鎖的差別。全域鎖即類鎖。此時不管是一個phone或多個phone都來自於同一個類別Phone類別。現在不管你鎖到了哪個對象,我都要等他釋放完了這個鎖才能使用。
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
一個靜態,一個普通。鎖的是同一支手機。靜態方法鎖的是Class.相當於我們鎖了一個校門,一個是普通同步方法,鎖的是目前物件。比如教師普通的們。鎖的對像不一樣。就不衝突
######8.1個靜態同步方法,1個普通同步方法,兩部手機,請問先印郵件還是簡訊######/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}######### ###解釋:這個跟上面是一樣的。 #########8鎖定理論解釋######
1.一個物件裡面如果有多個syncrhonized方法,某一時刻內,只要有一個線程去調用其中的一個synchronized方法了,其他的線程都只能等待,換句話說,某一刻內,只能有唯一一個執行緒去存取這些synchronized方法。
鎖的是目前物件this,被鎖定後,其他的執行緒都無法進入到目前物件的其他synchronized方法
加個普通方法後發現和同步鎖定無關。
換乘兩個物件後,不是同一把鎖了,情況立刻改變。
都換成靜態同步方法後,情況立刻改變
所有的非靜態同步方法用的都是同一把鎖------實例物件本身
2.synchronized實現同步的基礎:java中的每個物件都可以作為鎖。
具體表現為以下3種形式:
- 對於普通同步方法,鎖是目前實例物件
- 對於同步方法區塊,鎖定是synchronized括號裡面配置的物件。
例如在方法裡寫
synchronized(this){
} - #對於靜態同步方法,鎖定是目前類別的Class物件。
當一個行程試圖存取同步程式碼區塊時,它首先必須得到鎖,退出或拋出例外必須釋放鎖。
也就是說一個實例物件的非靜態同步方法取得鎖定後,該實例物件的其他非靜態同步方法必須等待取得鎖定的方法釋放鎖定後才能取得鎖定。可是別的實例物件的非靜態同步方法因為跟該實例物件的非靜態同步方法用的是不同的鎖,所以無需等待該實例物件已取得鎖的非靜態同步方法釋放鎖就可以取得自己的鎖。
所有的靜態同步方法用的也是同一把鎖-----類別物件本身。
這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。 (問題78)。即一個鎖class,一個鎖this,兩者不衝突。
但是一旦一個靜態同步方法取得鎖定後,其他的靜態同步方法都必須等待該方法釋放鎖定後才能取得鎖定。而不管是同一個實例物件的靜態方法之間,或是不同的實例物件的靜態同步方法之間,只要它們同一個類別的實例物件。 (問題56)
以上是Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文討論了各種Java垃圾收集算法(串行,並行,CMS,G1,ZGC),它們的性能影響和適合大量堆的應用。

本文討論了Java虛擬機(JVM),詳細介紹了其在不同平台運行Java程序中的作用。它說明了JVM的內部流程,密鑰組件,內存管理,垃圾收集和性能Optimizatio

Java的Nashorn Engine可以在Java應用程序中啟用JavaScript腳本。關鍵步驟包括設置Nashorn,管理腳本和優化性能。主要問題涉及安全性,內存管理和未來兼容性

Java的Try-with-Resources通過自動關閉文件流或數據庫連接等資源來簡化資源管理,從而提高代碼可讀性和可維護性。

Java枚舉代表固定的值集,通過自定義方法和構造函數提供類型安全性,可讀性和其他功能。它們增強了代碼組織,可用於開關語句中以進行有效的價值處理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

Atom編輯器mac版下載
最受歡迎的的開源編輯器