Java多線程技術(shù)總結(jié)-鎖的使用

我們前篇介紹了點關(guān)于線程創(chuàng)建的方式以及Thread相關(guān)api的介紹。這次我們說說線程中鎖的應(yīng)用。多線程中,數(shù)據(jù)同步是一個很讓人頭疼的事情,并且寫代碼中我們很容易寫出線程不安全的代碼,在查問題的時候也是特別不容易的查出來。java中在線程同步中采取了鎖的方式來讓數(shù)據(jù)同步。

synchronized 關(guān)鍵字 使用

  1. 把非線程安全的變成線程安全的。在方法名前面加上該關(guān)鍵字即可。
 public synchronized String  getContent(){
        return null ;
    }

雖然這兩種方法中都可以形成線程安全,但是如果在操作中不當,也會出現(xiàn)線程不安全的結(jié)果。我們在方法中有鎖,如果我們在該類上創(chuàng)建多個實例,那么鎖的作用就會消失。還會出現(xiàn)線程不安全的狀況。在項目中如果方法中加鎖,最好采用的是同一個類或者是靜態(tài)方法,這樣保證使用的是同一個鎖,不會是多個鎖。保證了線程安全的問題。方法上加鎖,如果在方法中有很多代碼其實不需要執(zhí)行同步操作,只是一部分需要同步操作,在整個方法上加鎖,就容易導(dǎo)致該方法區(qū)的內(nèi)容運行過慢,效率降低。

public  static synchronized String  getContent(){
        return null ;
    }
  1. 使用該關(guān)鍵字,形成同步代碼塊。
    同步代碼塊可以幫助解決上面的問題。將一部分同步,一部分異步.這樣同步的地方就可以并行執(zhí)行,增大效率。
public  String getContent(Object object){

         Stirng result ;
        synchronized (Object.class){
            return null ;
        }
        return result;
    }
  1. 同步代碼塊與在方法區(qū)上使用synchronized關(guān)鍵字的作用
    1. 在調(diào)用時,呈現(xiàn)阻塞的狀態(tài)。
    2. 同一時間內(nèi),只有一個線程可以調(diào)用代碼塊中的代碼
  2. 同步代碼塊還支持其他對象來實現(xiàn)同步的功能
    • 代碼塊要求的是()中的對象監(jiān)視器,并且在同步代碼塊中我們使用的同一個對象,那么在代碼塊中的監(jiān)視器就可以是this或者其他的非this對象,但是對于類似Stirng或者Integer這種不變的對象不可用。無法鎖定一個對象,在多線程時刻容易出現(xiàn)線程安全問題。

volatile 關(guān)鍵字

  • 使變量在多個線程之間可見。我們都是到在線程中會有私有堆棧和共有堆棧,那么volatile 的作用就是讓其在線程訪問變量時,強制性的從共有堆棧中取值。也就是我們平常所說的主內(nèi)存而不是線程工作內(nèi)容中讀取,保證了線程安全的可見性。但是只是保證可見性,不保證原子性。沒有同步特性。

Lock的使用

  1. ReentrantLock 介紹
    ReentrantLock 可以達到我們使用synchronized 鎖達到的同步效果 ,并且還能擴展更強大。在使用中我們一般使用的是以下一些方法。并且該鎖是一個完全互斥拍他的鎖。讀寫不分離
    • lock(): 獲得鎖。
    • unlock(): 釋放鎖。該方法使用一般都會放在finally中 ,如果線程出現(xiàn)異常退出,應(yīng)該把鎖也釋放掉,讓其他新城也獲得該鎖。程序能繼續(xù)執(zhí)行.
    • Condition 實現(xiàn)等待/通知 。如果我們想實現(xiàn)單個對單個的通知,那么我們可以創(chuàng)建多個Condition來幫助我們實現(xiàn)一對一的方式。Condition中有await和signal 還有signalAll();await實現(xiàn)的是等待的方式,signal
      實現(xiàn)的是通知等待的線程繼續(xù)執(zhí)行。我們在使用該等待方式之前必須,先獲得鎖才能使用,不然獲得就是異常.
    • 公平鎖與非公平鎖:公平鎖是在先進來的線程會先獲得資源。非公平鎖先進來的線程不一定會先獲得鎖,可能有的線程一直拿著鎖不放,容易造成線程鎖之間的不公平。
    • 簡單Api介紹
     public  void  getContent(Integer value ){
        try{
            lock.lock();
             lock.getHoldCount(); //查詢當前線程保持的此鎖定的個數(shù)。也就是調(diào)用lock()方法的次數(shù)。
            lock.getQueueLength(); // 返回掙等待獲取此鎖定 的線程估計數(shù)。
            lock.getWaitQueueLength(condition); //返回等待與此鎖定相關(guān)條件Condition估計數(shù)。
            lock.hasQueuedThread(Thread threads) ; //作用查詢指定的線程是否在等待獲取此鎖定
            lock.hasQueuedThreads(); //查詢 是否有線程正在等待獲取此鎖定。
            lock.hasWaiters(condition); // 查詢是否有線程正在等待此鎖定有關(guān)的condition條件。
            lock.isFair(); // 判斷是不是公平鎖
            lock.isHeldByCurrentThread(); // 查詢當前線程是否保持此鎖定
            lock.isLocked(); //作用是查詢此鎖定是否由任意線程保持。
            lock.lockInterruptibly(); // 如果當前線程未被中斷,則獲取鎖定。如果已經(jīng)被中斷則出現(xiàn)異常
            lock.tryLock();  //僅在 調(diào)用時鎖定未被另一個線程保持的情況下,才獲取該鎖定
            System.out.println("打印內(nèi)容: " + Instant.now());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
  2. ReentrantReadWriteLock 讀寫鎖
  • 該鎖方便的在于讀寫鎖進行分離,我們在操作時讀鎖與讀鎖互不影響,那么就可以提高我們在程序中的效率。
  • 讀鎖與讀鎖之間互不影響,能共同存在,不排斥。
  • 讀鎖與寫鎖之間,讀鎖與寫鎖互斥,讀取數(shù)據(jù)時寫鎖不能執(zhí)行。一鎖執(zhí)行
  • 寫鎖與寫鎖之間,也互斥,同時只能一個鎖在執(zhí)行。
       ReentrantReadWriteLock  readWriteLock = new ReentrantReadWriteLock();
       readWriteLock.readLock().lock();
      readWriteLock.writeLock().lock();
TIM截圖20180405235154.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容