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

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

公平鎖和非公平鎖

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

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

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

區(qū)別:

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

公平鎖,就是很公平,在并發(fā)環(huán)境下,每個(gè)線程在獲取鎖時(shí)會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果為空,或者當(dāng)前線程是等待隊(duì)列的第一個(gè),就占有鎖,否則就會(huì)加入到等待隊(duì)列中,以后會(huì)安裝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.

非公平鎖比較野蠻,上來(lái)就直接嘗試占有鎖,如果嘗試失敗,就再采用類(lèi)似公平鎖那種方式

對(duì)于Java ReentrantLock而言:

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

對(duì)于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)層方法會(huì)自動(dòng)獲取鎖。也就是說(shuō),線程可以進(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)層方法會(huì)自動(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ì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會(huì)消耗CPU。

package com.zixin;

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

/**
 * @ClassName SpinLockDemo
 * @Description 手寫(xiě)一個(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è)線程所持有,對(duì)ReentrantLock和Synchronized而言都是獨(dú)占鎖、

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

對(duì)ReentrantReadWriteLock其讀鎖是共享鎖,其寫(xiě)鎖是獨(dú)占鎖。

讀鎖的共享鎖可保證并發(fā)讀是非常高效的,讀寫(xiě),寫(xiě)讀,寫(xiě)寫(xiě)的過(guò)程是互斥的。

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()+" 正在寫(xiě)入:"+key);
            TimeUnit.MILLISECONDS.sleep(500);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+" 寫(xiě)入完成:"+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 讀寫(xiě)鎖
 * @Author zixin
 * @Date 2019/12/30 11:38
 * @Version 1.0
 **/
public class ReadWriteLockDemo {

    /**
     * 0 正在寫(xiě)入:0
     * 0 寫(xiě)入完成:0
     * 1 正在寫(xiě)入:1
     * 1 寫(xiě)入完成:1
     * 2 正在寫(xiě)入:2
     * 2 寫(xiě)入完成:2
     * 3 正在寫(xiě)入:3
     * 3 寫(xiě)入完成:3
     * 4 正在寫(xiě)入:4
     * 4 寫(xiě)入完成:4
     * 0 正在讀?。?
     * 1 正在讀?。?
     * 2 正在讀?。?
     * 3 正在讀取:3
     * 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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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