關於Java中的鎖與線程間通訊

公平鎖與非公平鎖

併發包中ReentrantLock的建立能夠指定構造函數的boolean類型來獲得公平鎖或者非公平鎖,默認是非公平鎖java

二者區別:

公平鎖:在併發環境中,每一個線程在獲取鎖時會先查看此鎖維護的等待隊列,若是爲空,或者當前線程是等待隊列中的第一個,就佔用鎖,不然就會加入到等待隊列中,之後會按照FIFO的規則從隊列中等待被取到。api

非公平鎖:非公平鎖比較粗魯上來就直接嘗試佔有鎖,若是嘗試失敗,就在採用相似公平鎖的方式在隊列中等待被取到。併發

對於java ReentrantLock而言,經過構造函數指定該鎖是否爲公平鎖,默認是非公平鎖。非公平鎖的優勢自安於吞吐量比公平鎖大。jvm

對於synchronized而言,也是一種非公平鎖函數

可重入鎖(遞歸鎖)

可重入鎖又叫遞歸鎖,典型的可重入鎖有ReentrantLock/Synchronized。指的是統一鮮橙外層函數得到鎖以後,內層度規函數仍然能獲取該鎖的代碼,同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖
也就是說,線程能夠進入任何一個他已經擁有的鎖所同步着的代碼塊。post

public synchronized void method01(){
        method02();
    }
    public synchronized void method02(){
        
    }
複製代碼

如以上代碼,若是一個線程擁有method01的鎖,那麼會自動擁有method02的鎖,這樣看,可重入鎖最大的做用是避免死鎖this

自旋鎖

可參考上篇文章介紹的CAS的加鎖方式atom

public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }
複製代碼

自旋鎖是指獲取鎖的線程不會當即阻塞,而是採用循環的方式去嘗試獲取鎖直至成功爲止,沒有相似wait的阻塞,這樣的好處是減小線程上下文切換的消耗,缺點是循環會消耗CPUspa

手動實現一個自旋鎖:線程

public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread +": come in lock");
        while (!atomicReference.compareAndSet(null,thread)){

        }
    }


public void unLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread + ": come in unlock");
        while (!atomicReference.compareAndSet(thread,null)){

        }
    }
複製代碼

當A線程調用myLock時,thread爲null,因此atomicReference.compareAndSet(null,thread)成立,取反跳出循環,這時atomicReference內Thread爲A的線程,B線程同時也調用myLock方法時,由於指望值爲null,其實是A線程,結果不成立,因此一直在while中循環;A線程再調用unlock方法,指望值是A本身的線程,而後設置爲null,返回true而後取反,跳出循環,B線程不斷地在mylock中循環,忽然讀到指望值爲null了,知足本身的需求,而後跳出循環,這時加鎖成功。

獨佔鎖(寫鎖)/共享鎖(讀鎖)/互斥鎖

獨佔鎖:該鎖一次只能被一個線程所持有,ReentrantLock和Synchronized都是獨佔鎖
共享鎖:該鎖可被多個線程所持有。 ReentrantReadWriteLock中的讀鎖是共享鎖,其寫鎖是獨佔鎖。 讀鎖的共享鎖可保證併發讀是很是高效的,讀寫,寫讀,寫寫的過程是互斥的。

CountDownLatch

讓一些線程阻塞直到另外一些線程完成一系列操做後才被喚醒 CountDownLatch主要有兩個方法,當一個或多個線程調用await方法時,調用線程會被阻塞。其餘線程調用countDown方法會將計數器減1(調用countDown方法的線程不會被阻塞),當計數器的值變成零時,因調用await方法被阻塞的線程會被喚醒,繼續執行。

CyclicBarrier

CyclicBarrier意思Wie可循環使用的屏障。主要功能是讓一組線程到達一個屏障點(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,被屏障攔截的線程纔會繼續幹活,線程進入屏障經過CyclicBarrier的await()方法。 demo: 集齊7顆龍珠才能召喚神龍

Semaphore

Semaphore 信號量,主要用於兩個目的,一個是用於多個共享資源的互斥使用,另外一個用於併發線程數的控制。

Synchronized 和 Lock有什麼區別? 用新的lock有什麼好處

  1. 構成角度
    synchronized是關鍵字屬於jvm層面,經過monitorenter(底層經過monitor對象來完成,wait/notify等方法也依賴於monitor對象,只有在同步塊或同步方法中才能調wait/notify等方法)、monitorexit來控制鎖 Lock是具體的實現類(java.util.concurrent.locks.lock),是api層面的鎖
  2. 使用方法 synchronized 不須要用戶手動釋放鎖,當synchronized代碼執行完後系統會自動讓線程釋放對鎖的佔用 reentrantlock須要用戶去手動釋放鎖,若沒有主動釋放鎖,就有可能致使出現死鎖現象。須要配合lock()和unlock()方法配合try/finally語句塊來完成。
  3. 等待是否可中斷
    synchronized不可中斷,除非拋異常或者正常運行完成
    reentrantLock可中斷:
    • 設置超時方法tryLock(long timeout,TimeUnit unit)
    • lockInterruptibly()放代碼塊中, 調用interrupt()方法可中斷
  4. 加鎖是否公平
    synchronized非公平鎖 reentrantlock默認非公平鎖,構造方法能夠傳入bolean設置是否公平鎖
  5. 綁定多個條件condition synchronized沒有條件設置只能隨機notify 或notifyAll reentrantlock用來實現分組喚醒須要喚醒的線程們,能夠精確喚醒,而不是像synchronized,要麼隨即喚醒一個線程要麼喚醒所有線程
相關文章
相關標籤/搜索