公平鎖和非公平鎖&可重入鎖&自旋鎖&獨(dú)占鎖/共享鎖

文章同步更新在個(gè)人公眾號“梓莘”,歡迎大家關(guān)注钥星,相互交流控汉。

公平鎖和非公平鎖

公平鎖:是指多個(gè)線程按照申請鎖的順序來獲取鎖,也就是遵循先來后到

非公平鎖:是指多個(gè)線程獲取鎖的順序并不是安裝申請鎖的順序腥沽,有可能后申請鎖的線程優(yōu)先獲得鎖,在高并發(fā)環(huán)境下鸠蚪,有可能造成優(yōu)先級反轉(zhuǎn)或者饑餓現(xiàn)象今阳。非公平就是允許加塞

在并發(fā)包ReentrantLock的創(chuàng)建可以執(zhí)行構(gòu)造函數(shù)的boolean類型來得到公平鎖和非公平鎖师溅,默認(rèn)是非公平鎖。

區(qū)別:

公平鎖:Threads acquire a fair lock in the order in which they required it

公平鎖盾舌,就是很公平墓臭,在并發(fā)環(huán)境下,每個(gè)線程在獲取鎖時(shí)會先查看此鎖維護(hù)的等待隊(duì)列妖谴,如果為空窿锉,或者當(dāng)前線程是等待隊(duì)列的第一個(gè),就占有鎖膝舅,否則就會加入到等待隊(duì)列中嗡载,以后會安裝FIFO的規(guī)則從隊(duì)列充取到自己。

非公平鎖:a nonfair lock permits barging:threads requesting a lock can jump ahead of the qyeye of waiting threads if the lock happend to be available when it is requested.

非公平鎖比較野蠻仍稀,上來就直接嘗試占有鎖洼滚,如果嘗試失敗,就再采用類似公平鎖那種方式

對于Java ReentrantLock而言:

通過構(gòu)造函數(shù)指定該鎖是否是公平鎖琳轿,默認(rèn)是非公平鎖判沟,非公平鎖的優(yōu)點(diǎn)在于吞吐量比公平鎖大耿芹。

對于synchronized而言崭篡,也是一種非公平鎖。

   /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
  public ReentrantLock() {
        sync = new NonfairSync();
    }

/**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
 public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

可重入鎖

指的是同一線程外層函數(shù)獲得鎖之后吧秕,內(nèi)層遞歸函數(shù)仍然能獲得該鎖的代碼琉闪,在同一個(gè)線程在外層方法獲得鎖的時(shí)候,在進(jìn)入內(nèi)層方法會自動(dòng)獲取鎖砸彬。也就是說颠毙,線程可以進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊。

package com.zixin;

class Photo{
    public synchronized void sendSms() throws Exception{
        System.out.println(Thread.currentThread().getId()+"  invoked sendSMS");
        sendEmail();
    }

    public synchronized void sendEmail() throws Exception{
        System.out.println(Thread.currentThread().getId()+"  invoked sendEmail");

    }
}
/**
 * @ClassName ReenterLockDemo
 * @Description 指的是同一線程外層函數(shù)獲得鎖之后砂碉,內(nèi)層遞歸函數(shù)仍然能獲得該鎖的代碼蛀蜜,在同一個(gè)線程在外層方法獲得鎖的時(shí)候,在進(jìn)入內(nèi)層方法會自動(dòng)獲取鎖增蹭。也就是鎖滴某,線程可以進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊。
 * @Author zishen
 * @Date 2019/12/30 9:36
 * @Version 1.0
 **/
public class ReenterLockDemo {

    /**
     * 11  invoked sendSMS
     * 11  invoked sendEmail
     * 10  invoked sendSMS
     * 10  invoked sendEmail
     * @param args
     */
    public static void main(String[] args) {
        Photo p = new Photo();
        new Thread(()->{
            try {
                p.sendSms();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();
        new Thread(()->{
            try {
                p.sendSms();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();
    }

}

自旋鎖

嘗試獲取鎖的線程不會立即阻塞滋迈,而是采用循環(huán)的方式去嘗試獲取鎖霎奢,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會消耗CPU饼灿。

package com.zixin;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName SpinLockDemo
 * @Description 手寫一個(gè)自旋鎖
 * @Author zixin
 * @Date 2019/12/30 10:34
 * @Version 1.0
 **/
public class SpinLockDemo {
    //原子引用線程
    AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+" come in");
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }
    public void myUnLock(){
        Thread thread =Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+" invoked myUnLock");
    }

    /**
     * AA come in
     * BB come in
     * AA invoked myUnLock
     * BB invoked myUnLock
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {

        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(()->{
            spinLockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
                spinLockDemo.myUnLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"AA").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            spinLockDemo.myLock();
            spinLockDemo.myUnLock();
        },"BB").start();
    }
}

獨(dú)占鎖/共享鎖

獨(dú)占鎖:指該鎖一次只能被一個(gè)線程所持有幕侠,對ReentrantLock和Synchronized而言都是獨(dú)占鎖、

共享鎖:指該鎖可被多個(gè)線程多持有碍彭。

對ReentrantReadWriteLock其讀鎖是共享鎖晤硕,其寫鎖是獨(dú)占鎖悼潭。

讀鎖的共享鎖可保證并發(fā)讀是非常高效的,讀寫窗骑,寫讀女责,寫寫的過程是互斥的。

package com.zixin;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();

    private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
    public void put(String key,Object value){
        rwlock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName()+" 正在寫入:"+key);
            TimeUnit.MILLISECONDS.sleep(500);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+" 寫入完成:"+key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rwlock.writeLock().unlock();
        }

    }
    public void get(String key){
        rwlock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+" 正在讀却匆搿:"+key);
            TimeUnit.MILLISECONDS.sleep(500);
            Object result = map.get(key);
            System.out.println(Thread.currentThread().getName()+" 讀取完成:"+result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rwlock.readLock().unlock();
        }

    }
    public void clearMap(){
        map.clear();
    }
}
/**
 * @ClassName ReadWriteLockDemo
 * @Description 讀寫鎖
 * @Author zixin
 * @Date 2019/12/30 11:38
 * @Version 1.0
 **/
public class ReadWriteLockDemo {

    /**
     * 0 正在寫入:0
     * 0 寫入完成:0
     * 1 正在寫入:1
     * 1 寫入完成:1
     * 2 正在寫入:2
     * 2 寫入完成:2
     * 3 正在寫入:3
     * 3 寫入完成:3
     * 4 正在寫入:4
     * 4 寫入完成:4
     * 0 正在讀鹊种:0
     * 1 正在讀取:1
     * 2 正在讀热碜濉:2
     * 3 正在讀人⑾病:3
     * 4 正在讀取:4
     * 1 讀取完成:1
     * 2 讀取完成:2
     * 0 讀取完成:0
     * 3 讀取完成:3
     * 4 讀取完成:4
     * @param args
     */
    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 0; i <5 ; i++) {
            final int tempInt = i;
            new Thread(()->{
                myCache.put(tempInt+"",tempInt+"");
            },String.valueOf(i)).start();
        }

        for (int i = 0; i <5 ; i++) {
            final int tempInt = i;
            new Thread(()->{
                myCache.get(tempInt+"");
            },String.valueOf(i)).start();
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末立砸,一起剝皮案震驚了整個(gè)濱河市掖疮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颗祝,老刑警劉巖浊闪,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異螺戳,居然都是意外死亡搁宾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門倔幼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盖腿,“玉大人,你說我怎么就攤上這事损同◆娓” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵膏燃,是天一觀的道長茂卦。 經(jīng)常有香客問我,道長组哩,這世上最難降的妖魔是什么等龙? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮禁炒,結(jié)果婚禮上而咆,老公的妹妹穿的比我還像新娘。我一直安慰自己幕袱,他們只是感情好暴备,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著们豌,像睡著了一般涯捻。 火紅的嫁衣襯著肌膚如雪浅妆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天障癌,我揣著相機(jī)與錄音凌外,去河邊找鬼。 笑死涛浙,一個(gè)胖子當(dāng)著我的面吹牛康辑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播轿亮,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疮薇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了我注?” 一聲冷哼從身側(cè)響起按咒,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎但骨,沒想到半個(gè)月后励七,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奔缠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年掠抬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片添坊。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剿另,死狀恐怖箫锤,靈堂內(nèi)的尸體忽然破棺而出贬蛙,到底是詐尸還是另有隱情,我是刑警寧澤谚攒,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布阳准,位于F島的核電站,受9級特大地震影響馏臭,放射性物質(zhì)發(fā)生泄漏野蝇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一括儒、第九天 我趴在偏房一處隱蔽的房頂上張望绕沈。 院中可真熱鬧,春花似錦帮寻、人聲如沸乍狐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浅蚪。三九已至藕帜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惜傲,已是汗流浹背洽故。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盗誊,地道東北人时甚。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像哈踱,于是被迫代替她去往敵國和親撞秋。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容