【JUC并发编程06】多线程锁 (公平锁和非公平锁,死锁,可重锁)
文章目錄
- 6 多線程鎖 (公平鎖和非公平鎖,死鎖,可重鎖)
- 6.1 synchronized 鎖的八種情況
- 6.2 對上述例子的總結
- 6.3 公平鎖和非公平鎖
- 6.4 可重入鎖
- 6.5 死鎖
6 多線程鎖 (公平鎖和非公平鎖,死鎖,可重鎖)
某一個時刻內,只能有唯一一個線程去訪問這些synchronized 方法
所有的 靜態同步方法用的也是同一把鎖 ——類對象本身,這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的,但是一旦一個靜態同步方法獲取鎖后,其他的靜態同步方法都必須等待該方法釋放鎖后才能獲取鎖,而不管是同一個實例對象的靜態同步方法之間,還是不同的實例對象的靜態同步方法之間,只要它們同一個類的實例對象
synchronized 鎖的是方法,則是對象鎖,同個對象鎖的機制要等待,不同對象鎖的機制調用同一個不用等待
加了static則為class鎖而不是對象鎖
對于同步方法塊,鎖是 synchronized 括號里配置對象
6.1 synchronized 鎖的八種情況
通過具體例子進行分析
class Phone {public synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception {System.out.println("------sendEmail");}public void getHello() {System.out.println("------getHello");} }public class SynchronizedLockTest {public static void main(String[] args) throws Exception {Phone phone = new Phone();Phone phone2 = new Phone();new Thread(() -> {try {phone.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "A").start();Thread.sleep(100);new Thread(() -> {try {// phone.sendEmail();// phone.getHello();phone2.sendEmail();} catch (Exception e) {e.printStackTrace();}}, "B").start();} }不同案例輸出的不同結果
1 標準訪問,先打印短信還是郵件
------sendSMS
------sendEmail
2 停4秒在短信方法內,先打印短信還是郵件
------sendSMS
------sendEmail
3 新增普通的hello方法,是先打短信還是hello
------getHello
------sendSMS
4 現在有兩部手機,先打印短信還是郵件
------sendEmail
------sendSMS
5 兩個靜態同步方法,1部手機,先打印短信還是郵件
------sendSMS
------sendEmail
6 兩個靜態同步方法,2部手機,先打印短信還是郵件
------sendSMS
------sendEmail
7 1個靜態同步方法,1個普通同步方法,1部手機,先打印短信還是郵件
------sendEmail
------sendSMS
8 1個靜態同步方法,1個普通同步方法,2部手機,先打印短信還是郵件
------sendEmail
------sendSMS
6.2 對上述例子的總結
同樣的對象訪問不同的同步鎖,是按照順序執行
同樣的對象訪問同步鎖與不同步鎖,是先不同步鎖執行
不同對象訪問不同同步鎖,按照順序執行
同一對象訪問不同靜態同步鎖,按照順序執行
不同對象訪問不同靜態同步鎖,按照順序執行
同一對象訪問一個靜態同步鎖,一個同步鎖,先執行同步鎖
不同對象訪問一個靜態同步鎖,一個同步鎖,先執行同步鎖,即先出同步鎖在出靜態同步鎖
概括來說,鎖之間的執行順序是:不同步鎖 > 同步鎖 > 靜態同步鎖
6.3 公平鎖和非公平鎖
- 公平鎖:效率相對低 ,但是cpu 的利用高了
- 非公平鎖:效率高,但是線程容易餓死(所有的工作,有一個線程完成)
用法: 在創建可重入鎖時,想構造器中傳入true
private final ReentrantLock lock = new ReentrantLock(true);因為 ReentrantLock 的構造器源碼如下:
// 在沒有傳入參數時,默認創建一個非公平鎖 public ReentrantLock() {sync = new NonfairSync(); } // 當傳入一個true值時,為公平鎖 public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync(); }6.4 可重入鎖
synchronized和lock都是可重入鎖
- sychronized是隱式鎖,不用手工上鎖與解鎖,而lock為顯示鎖,需要手工上鎖與解鎖
- 可重入鎖也叫遞歸鎖
而且有了可重入鎖之后,破解第一把之后就可以一直進入到內層結構
嵌套實現代碼 他能進入下一個鎖內而不會出現死鎖
synchronized的示例代碼
/*** 演示可重入鎖是什么意思,可重入,就是可以重復獲取相同的鎖而不會出現死鎖* synchronized和ReentrantLock都是可重入的* */ public class WhatReentrantSynchronized {// 創建一個鎖對象static Object mylock = new Object();public static void main(String[] args) {new Thread(()->{// 創建第一個鎖synchronized (mylock){System.out.println("這是第一層鎖");synchronized (mylock){System.out.println("這是第二層鎖");}}}).start();} }ReentrantLock的示例代碼
/*** lock和unlock的數量必須一致,否則會出現死鎖* */ public class WhatReentrantLock {public static void main(String[] args) {ReentrantLock lock = new ReentrantLock();new Thread(()->{// 上鎖lock.lock();try {System.out.println("這是第一層鎖");// 再次上鎖lock.lock();try{System.out.println("這是第二層鎖");}finally {lock.unlock();}}finally {lock.unlock();}}).start();} }6.5 死鎖
兩個或以上的進程因為爭奪資源而造成互相等待資源的現象稱為死鎖
產生死鎖的原因:
我們有時候不知道是否是死鎖 。那么怎么來驗證呢? (電腦配置的有環境變量,在命令窗口)
具體死鎖的操作代碼實列
可理解背下來,大廠面試可考,死鎖的簡單案例
總結
以上是生活随笔為你收集整理的【JUC并发编程06】多线程锁 (公平锁和非公平锁,死锁,可重锁)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【JUC并发编程05】集合的线程安全
- 下一篇: 【JUC并发编程07】Callable接