日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java多线程之8Lock问题解析

發布時間:2024/2/28 java 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程之8Lock问题解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java多線程之8Lock問題解析


本文目錄

1. 8Lock實例:
  • 標準訪問的時候,請問先打印郵件還是短信?
  • sendEmail方法暫停4秒鐘,請問先打印郵件還是短信?
  • 新增Hello普通方法,請問先打印郵件還是Hello?
  • 兩部手機,請問先打印郵件還是短信?
  • 兩個靜態同步方法,同1部手機 ,請問先打印郵件還是短信?
  • 兩個靜態同步方法,有2部手機 ,請問先打印郵件還是短信?
  • 1個靜態同步方法,1個普通同步方法,有1部手機 ,請問先打印郵件還是短信?
  • 1個靜態同步方法,1個普通同步方法,有2部手機 ,請問先打印郵件還是短信?
  • 2. 8Lock總結
    3. 補充:當前類的Class對象和當前類的實例對象分別是什么?

    8Lock實例:


    1. 標準訪問的時候,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public synchronized void sendEmail() {System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");} } //主方法 public class Lock_8 {public static void main(String[] args) {Phone p=new Phone();new Thread(() ->{p.sendEmail();},"A").start();new Thread(() ->{p.getSMS();;},"B").start();} }

    結果:


    解析:

    • 不知道,因為線程誰搶到了誰執行,一般情況下是A執行

    2. sendEmail方法暫停4秒鐘,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public synchronized void sendEmail() {Thread.sleep(4000);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{p.sendEmail();},"A").start();//強制讓線程A先執行Thread.sleep(200);new Thread(() ->{p.getSMS();;},"B").start();} }

    結果:


    解析:

    • 4秒后A先執行,緊接著B執行。
    • 因為休眠main線程之前A已經啟動了,時間足夠A運行,A會鎖住資源類的入口(也就是對象)。所以A先執行。

    3. 新增Hello普通方法,請問先打印郵件還是Hello?


    代碼:

    //資源類 class Phone{public synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(200);new Thread(() ->{p.sayHello();},"B").start();} }

    結果:


    解析:

    • 先打印hello,雖然sendEmail鎖住了資源類的入口(對象),因為sayHello未上鎖,所以sayHello方法可以進入資源類。
    • 但是Thread.sleep()鎖住了main線程,也就是hello打印出來的延遲時間就是休眠的設定時間。
    加個普通方法后發現和同步鎖無關

    4. 兩部手機,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(2000);new Thread(() ->{p2.getSMS();},"B").start();} }

    結果:


    解析:

    • 先打印SMS,因為鎖的是資源類的入口,也就是對象,既然不是同一個對象,那肯定鎖不住。并且線程B的執行和main線程的休眠時間相關。
    換成兩個對象后,不是同一把鎖了,情況立刻變化。

    5. 兩個靜態同步方法,同1部手機 ,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public static synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(5000);new Thread(() ->{p.getSMS();},"B").start();} }

    結果:


    解析:

    • 先打印sendEmali,然后打印getSMS,因為靜態同步鎖,鎖的是Phone.Class,所以B線程在A線程執行完之前進不去。
    • synchronized實現同步的基礎:Java中的每一個對象都可以作為鎖。

    具體表現為以下3種形式。

    1. 對于普通同步方法,鎖是當前實例對象。
    2. 對于靜態同步方法,鎖是當前類的Class對象。
    3. 對于同步方法塊,鎖是Synchonized括號里配置的對象。

    6. 兩個靜態同步方法,有2部手機 ,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public static synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(5000);new Thread(() ->{p2.getSMS();},"B").start();} }

    結果:


    解析:

    • 看似和5不一樣,其實是一回事,雖然兩個對象,因為強制A先執行,所以A會鎖住資源類,因此先打印sendEmail。

    7. 1個靜態同步方法,1個普通同步方法,有1部手機 ,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(2);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(1000);new Thread(() ->{p.getSMS();},"B").start();} }

    結果:


    解析:

    • static方法鎖鎖的不是資源類,鎖的是類對象,也就是說,不管new了幾個,靜態同步方法的類對象都是一個;而普通同步方法鎖住的是new出來的對象。
    • 所有的靜態同步方法用的也是同一把鎖——類對象本身,
      這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。
      但是一旦一個靜態同步方法獲取鎖后,其他的靜態同步方法都必須等待該方法釋放鎖后才能獲取鎖,
      而不管是否是同一個實例對象。

    8. 1個靜態同步方法,1個普通同步方法,有2部手機 ,請問先打印郵件還是短信?


    代碼:

    //資源類 class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");} } //主方法 public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//強制讓線程A先執行Thread.sleep(1000);new Thread(() ->{p2.getSMS();},"B").start();} }

    結果:


    解析:

    • P1鎖住的不是資源類,而是類對象。線程1鎖的是類對象,線程2鎖的是實例對象,雖然看似是一個對象,然而兩者不具備競態條件,因此修改main休眠時間之后就會發現getSMS先執行。

    8Lock總結

  • 一個對象里面如果有多個synchronized方法,某一個時刻內,只要一個線程去調用其中的一個synchronized方法了,其它的線程都只能等待,換句話說,某一個時刻內,只能有唯一一個線程去訪問這些synchronized方法
  • 鎖的是當前對象this,被鎖定后,其它的線程都不能進入到當前對象的其它的synchronized方法
  • 加個普通方法后發現和同步鎖無關
  • 換成兩個對象后,不是同一把鎖了,情況立刻變化。
  • 都換成靜態同步方法后,情況又變化
  • 所有的非靜態同步方法用的都是同一把鎖——實例對象本身,也就是說如果一個實例對象的非靜態同步方法獲取鎖后,該實例對象的其他非靜態同步方法必須等待獲取鎖的方法釋放鎖后才能獲取鎖,可是別的實例對象的非靜態同步方法因為跟該實例對象的非靜態同步方法用的是不同的鎖,所以毋須等待該實例對象已獲取鎖的非靜態同步方法釋放鎖就可以獲取他們自己的鎖。
  • 所有的靜態同步方法用的也是同一把鎖——類對象本身,這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。但是一旦一個靜態同步方法獲取鎖后,其他的靜態同步方法都必須等待該方法釋放鎖后才能獲取鎖,而不管是同一個實例對象的靜態同步方法之間,還是不同的實例對象的靜態同步方法之間,只要它們同一個類的實例對象!
  • 一個靜態同步方法 一個普通同步方法,一個非同步方法,那么三者是都不具備競態條件的。

  • 3. 補充:當前類的Class對象和當前類的實例對象分別是什么?

    實例:

    • 簡單理解,就是new,就是對類的實例化,創建這個類對應的實際對象,類只是對事物的描述,而實例化就相當于為這個描述新開辟了一塊內存,可以改變這塊區域里的各種屬性(成員變量),當然,也可以實例化多塊區域,只是不同的對象而已。

    Class:

    • 注意這里C大寫了,與類概念區分開,在java里,Class是一個實實在在的類,在包 java.lang 下,有這樣一個Class.java文件,它跟我們自己定義的類一樣,是一個實實在在的類,Class對象就是這個Class類的實例了。在Java里,所有的類的根源都是Object類,而Class也不例外,它是繼承自Object的一個特殊的類,它內部可以記錄類的成員、接口等信息,也就是在Java里,Class是一個用來表示類的類。(o(∩_∩)o 有點繞啊,抓住關鍵一點,Class是一個實實在在的類,可以為它創建實例,也就是本文后面提到的Class對象,也看叫做Class實例)。

    java提供了下面幾種獲取到類的Class對象的方法:

    1) 利用對象實例調用getClass()方法獲取該對象的Class實例;
    2) 使用Class類的靜態方法forName(“包名+類名”),用類的名字獲取一個Class實例
    3) 運用 類名.class 的方式來獲取Class實例;

    我們知道java世界是運行在JVM之上的,我們編寫的類代碼,在經過編譯器編譯之后,會為每個類生成對應的.class文件,這個就是JVM可以加載執行的字節碼。運行時期間,當我們需要實例化任何一個類時,JVM會首先嘗試看看在內存中是否有這個類,如果有,那么會直接創建類實例;如果沒有,那么就會根據類名去加載這個類,當加載一個類,或者當加載器(class loader)的defineClass()被JVM調用,便會為這個類產生一個Class對象(一個Class類的實例),用來表達這個類,該類的所有實例都共同擁有著這個Class對象,而且是唯一的。

    總結

    以上是生活随笔為你收集整理的Java多线程之8Lock问题解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。