?通過8種情況演示鎖運行案例,看看我們到底鎖的是什么
1鎖相關的8種案例演示code
package com.bilibili.juc.lock;import java.util.concurrent.TimeUnit;/*** 題目:談談你對多線程鎖的理解,8鎖案例說明* 口訣:線程 操作 資源類* 8鎖案例說明:* 1. 標準訪問ab兩個線程,請問先打印郵件還是短信? --------先郵件,后短信 共用一個對象鎖* 2. sendEmail鐘加入暫停3秒鐘,請問先打印郵件還是短信?--------先郵件,后短信 共用一個對象鎖* 3. 添加一個普通的hello方法,請問先打印普通方法還是郵件? --------先hello,再郵件 資源沒有爭搶,hello方法沒有用到對象鎖* 4. 有兩部手機,請問先打印郵件還是短信? --------先短信后郵件 資源沒有爭搶,不是同一個對象鎖* 5. 有兩個靜態同步方法,一部手機, 請問先打印郵件還是短信?--------先郵件后短信 共用一個類鎖* 6. 有兩個靜態同步方法,兩部手機, 請問先打印郵件還是短信? --------先郵件后短信 共用一個類鎖* 7. 有一個靜態同步方法,一個普通同步方法,一部手機,請問先打印郵件還是短信? --------先短信后郵件 一個類鎖一個對象鎖* 8. 有一個靜態同步方法,一個普通同步方法,兩部手機,請問先打印郵件還是短信? ---------先短信后郵件 一個類鎖一個對象鎖*/
public class Lock8Demo {public static void main(String[] args) {Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> phone.sendEmail(), "a").start();// 暫停200毫秒,保證線程先啟動try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> /*phone.sendSMS()*/ /*phone.hello()*/ phone2.sendSMS(), "b").start();}}// 資源類
class Phone {public static synchronized void sendEmail() {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("--------sendEmail--------");}public /*static*/ synchronized void sendSMS() {System.out.println("--------sendSMS--------");}public void hello() {System.out.println("--------hello--------");}
}
2案例總結
1-2:
一個對象里面如果有多個 synchronized 方法,某一個時刻內,只要一個線程去調用其中的一個synchronized方法,其它線程都只能等待。換句話說,某一個時刻內,只能有唯一的一個線程去訪問這些synchronized方法。鎖的是當前對象this,被鎖定后,其它線程都不能進入到當前對象的其它的synchronized方法
3-4:
加個普通方法后發現和同步鎖無關
換成兩個對象后,不是同一把鎖了,情況立即變化
5-6:
都換成靜態同步方法后,情況又變化
三種synchronized鎖的內容有一些差別:
對于普通同步方法(被synchronized修飾的成員方法),鎖的是當前實例對象,通常指this,所有的同步方法用的都是同一把鎖—>實例對象本身(即Phone phone = new Phone();)
對于靜態同步方法(被synchronized修飾的靜態方法),鎖的是當前類的Class對象,即Phone.class唯一的一個模板
對于同步方法塊,鎖的是synchronized括號內的對象
7-8:
當一個線程試圖訪問同步代碼時,它首先必須得到鎖,正常退出或拋出異常時必須釋放鎖
所有的普通同步方法用的都是同一把鎖——實例對象本身,就是new出來的具體實例對象本身,本類this。也就是說如果一個實例對象的普通同步方法獲取鎖后,該實例對象的其它普通同步方法必須等待獲取鎖的方法釋放鎖后才能獲取鎖
所有的靜態方法用的也是同一把鎖——類對象本身,就是我們說過的唯一模板class。具體實例對象this和唯一模板class,這兩把鎖是兩個不同的對象,所以靜態同步方法和普通同步方法之間是不會有競態條件的。但是一旦一個靜態同步方法獲取鎖后,其它的靜態同步方法都必須等待該方法釋放鎖后才能獲取鎖
如圖中Car Class就是模板,存放在虛擬機中的方法區/元空間,Car Class這個模板就只有一份。但是Car的實例對象,如:car1、car2、car3都在堆內存中,可以有多個。所以說Car Class和car實例加鎖的地方和對象都不一樣。運行效果也不一樣。
- 作用于實例方法,當前實例加鎖,進入同步代碼塊前要獲得當前實例的鎖;
- 作用于代碼塊,對括號里配置的對象加鎖
- 作用于靜態方法,當前類加鎖,進去同步代碼前要獲得當前類對象的鎖