溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

從構(gòu)建分布式秒殺系統(tǒng)聊聊為什么不用synchronized

發(fā)布時(shí)間:2020-03-23 00:06:40 來(lái)源:網(wǎng)絡(luò) 閱讀:389 作者:Java_老男孩 欄目:編程語(yǔ)言

前言

技術(shù)沒(méi)有高低之分,適合自己的就是最好的。只有努力擴(kuò)展自己的知識(shí)邊界,才能探索更多未知領(lǐng)域。

案例

在分析為什么不用 synchronized 這個(gè)問(wèn)題之前,我們先用代碼說(shuō)話,LockDemo 測(cè)試案例:

/**
 * 案例測(cè)試
 * @author 
 */
public class LockDemo {

    private static Lock lock = new ReentrantLock();

    private static int num1 = 0;
    private static int num2 = 0;
    public static void main(String[] args) {
        lockDemo();
        SyncDemo();
    }
    /**
     * 本機(jī)測(cè)試下20萬(wàn)自增基本能確定性能,但是不是特別明顯,50萬(wàn)差距還是挺大的
     * 20萬(wàn)以下數(shù)據(jù)synchronized優(yōu)于Lock
     * 20萬(wàn)以上數(shù)據(jù)Lock優(yōu)于synchronized
     */
    public static void lockDemo(){
        long start = System.currentTimeMillis();
        for(int i=0;i<500000;i++){
            final int num = i;
            new Runnable() {
                @Override
                public void run() {
                    lock(num);
                }
            }.run();
        }
        long end = System.currentTimeMillis();
        System.out.println("累加:"+num1);
        System.out.println("ReentrantLock鎖:"+ (end-start));
    }
    public static void SyncDemo(){
        long start = System.currentTimeMillis();
        for(int i=0;i<500000;i++){
            final int num = i;
            new Runnable() {
                @Override
                public void run() {
                    sync(num);
                }
            }.run();
        }
        long end = System.currentTimeMillis();
        System.out.println("累加:"+num2);
        System.out.println("synchronized鎖:"+ (end-start));
    }
    public static void lock(int i){
        lock.lock();
        num1 ++;
        lock.unlock();
    }
    public static synchronized void sync(int i){
        num2 ++;
    }
}

50萬(wàn)++測(cè)試數(shù)據(jù):

累加:500000
ReentrantLock鎖:20
累加:500000
synchronized鎖:28

用數(shù)據(jù)說(shuō)話,很明顯在高并發(fā)下,ReentrantLock 的性能是要優(yōu)于 synchronized 的,雖然僅僅是幾毫秒的差距,當(dāng)然這里我并沒(méi)有對(duì)比CPU的使用情況。

10萬(wàn)++測(cè)試數(shù)據(jù):

累加:100000
ReentrantLock鎖:13
累加:100000
synchronized鎖:8

分析

這時(shí)候小伙伴可能會(huì)問(wèn)了,有沒(méi)有一個(gè)準(zhǔn)確的臨界值,來(lái)區(qū)分使用這兩種鎖?當(dāng)然,在回答這個(gè)問(wèn)題之前,先了解一下這兩種鎖到底有何異同。

鎖的實(shí)現(xiàn)

Synchronized是依賴于JVM實(shí)現(xiàn)的,表現(xiàn)為原生語(yǔ)法層面的互斥鎖。開(kāi)發(fā)者是無(wú)法直接看到相關(guān)源碼,但是我們可以通過(guò)利用javap工具查看生成的class文件信息來(lái)分析Synchronize的實(shí)現(xiàn)。同步代碼塊是使用monitorenter和monitorexit指令實(shí)現(xiàn)的,同步方法依靠的是方法修飾符上的ACC_SYNCHRONIZED實(shí)現(xiàn)。

ReenTrantLock是基于JDK實(shí)現(xiàn)的,一個(gè)表現(xiàn)為API層面的互斥鎖,開(kāi)發(fā)人員通過(guò)查閱源碼就可以了解到。

可重入性

ReenTrantLock 的字面意思就是再進(jìn)入的鎖,synchronized關(guān)鍵字所使用的鎖也是可重入的,兩者關(guān)于這個(gè)的區(qū)別不大。

功能區(qū)別

Synchronized的使用比較方便,不需要開(kāi)發(fā)者手動(dòng)加鎖和釋放鎖,而ReenTrantLock需要手工聲明來(lái)加鎖和釋放鎖(lock() 和 unlock() 方法配合 try/finally 語(yǔ)句塊來(lái)實(shí)現(xiàn))

ReenTrantLock 在鎖的細(xì)粒度和靈活度上要優(yōu)于Synchronized。此外,還增加了一些高級(jí)特性,主要有以下3項(xiàng):等待可中斷、可實(shí)現(xiàn)公平鎖以及鎖可以綁定多個(gè)條件。

發(fā)展歷史

關(guān)于synchronized 與ReentrantLock

在JDK 1.6之后,虛擬機(jī)對(duì)于synchronized關(guān)鍵字進(jìn)行整體優(yōu)化后,在性能上synchronized與ReentrantLock已沒(méi)有明顯差距,因此在使用選擇上,需要根據(jù)場(chǎng)景而定,大部分情況下我們依然建議是synchronized關(guān)鍵字,原因之一是使用方便語(yǔ)義清晰,二是性能上虛擬機(jī)已為我們自動(dòng)優(yōu)化。而ReentrantLock提供了多樣化的同步特性,如超時(shí)獲取鎖、可以被中斷獲取鎖(synchronized的同步是不能中斷的)、等待喚醒機(jī)制的多個(gè)條件變量(Condition)等,因此當(dāng)我們確實(shí)需要使用到這些功能是,可以選擇ReentrantLock

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI