国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 雙重加鎖單例與 java 內(nèi)存重排序特性

HackerShell / 831人閱讀

摘要:關(guān)于對于重排序的講解,強(qiáng)烈推薦閱讀程曉明寫的深入理解內(nèi)存模型二重排序。語義語義單線程下,為了優(yōu)化可以對操作進(jìn)行重排序。編譯器和處理器為單個線程實現(xiàn)了語義,但對于多線程并不實現(xiàn)語義。雙重加載的單例模式分析即雙重檢查加鎖。

版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請注明出處:https://segmentfault.com/a/1190000009231182

1. 引言

在開始分析雙重加鎖單例代碼之前,我們需要先理解 java 內(nèi)存模式的重排序和無序?qū)懭胩匦浴?/p> 2. Java 內(nèi)存模型——重排序

在計算機(jī)中,軟件技術(shù)和硬件技術(shù)有一個共同的目標(biāo):在不改變程序執(zhí)行結(jié)果的前提下,盡可能的開發(fā)并行度。

同樣 Java 為了實現(xiàn)這一目標(biāo),在它的編譯和處理時會對代碼進(jìn)行重新排序,從而達(dá)到更高的并行度提升程序性能。

Java 在進(jìn)行重排序操作時會遵守數(shù)據(jù)依賴性,即編譯器和處理器不會改變存在數(shù)據(jù)依賴關(guān)系的兩個操作的執(zhí)行順序。

關(guān)于對于重排序的講解,強(qiáng)烈推薦閱讀程曉明寫的《深入理解Java內(nèi)存模型(二)——重排序》。

2.1 as-if-serial 語義

as-if-serial 語義
: 單線程下,為了優(yōu)化可以對操作進(jìn)行重排序。

Java 編譯器和處理器為單個線程實現(xiàn)了 as-if-serial 語義,但對于多線程并不實現(xiàn) as-if-serial 語義。

2.2 無序?qū)懭?/b>

若程序定義的變量之間沒有依賴關(guān)系,那么這兩個變量在 JVM 中的加載順序是不確定的。

3. 單例模式

單例模式帶來的好處:

方便共享通用的資源。

避免頻繁操作共享資源所帶來的性能消耗。

而我們已單例模式有有餓漢式(static 變量,在類加載時就進(jìn)行初始化一次)懶漢式(在使用到時才初始化一次)兩種,考慮到對于始初化單例類的開銷較大,往往我們需要創(chuàng)建單例是懶加載的,即在程序使用到單例時才創(chuàng)建,從而可以避免創(chuàng)建單例時拖慢程序的啟動速度。

所以對于使用單例模式有兩個要求:(1)懶加載。(2)多線程安全

3.1 雙重加載的單例模式分析

DCL(double-checked locking) 即雙重檢查加鎖。因為 DCL 模式的單例是懶加載的,所以這往往也是在許多項目中最容易見到的單例模式寫法。但是這種方式創(chuàng)建的單例,是多線程安全的嗎?

對于雙重檢查加載的單例代碼:

package com.wuxianjiezh.demo.threadpool;

public class Singleton {

    private static Singleton instance;

    // 私有化的構(gòu)造方法,保證外部的類不能通過構(gòu)造器來實例化
    private Singleton() {
    }

    // 雙重檢查加鎖來獲取對象單例
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

假設(shè)有二個線程要獲取上面的單例,當(dāng)其中 線程一 進(jìn)入同步塊執(zhí)行到 instance = new Singleton(); 時,線程二 來到了 外的第一個 null 判斷。注意這里,線程一 在執(zhí)行 instance = new Singleton(); 這段代碼時有以下幾個步驟,其中執(zhí)行是無序的(無序?qū)懭耄赡艹霈F(xiàn)下面這種情況:

// 1. 為 Singleton 對象分配內(nèi)存
memory = allocate();
// 2. 注意現(xiàn)在 instance 是非空的,但還沒初始化
instance = memory;
// 3. 調(diào)用 Singleton 的構(gòu)造函數(shù),傳遞 instance
ctorSingleton(instance);

當(dāng)在執(zhí)行到 instance = memory; 時,線程二 進(jìn)入了第一次的 null 判斷,此才 線程二 判斷 instance 不為 null,返回了 instance,但此時返回的不是單例的實例對象,而是內(nèi)存對象。

3.2 單例模式推薦寫法

使用靜態(tài)內(nèi)部類:

package com.wuxianjiezh.demo.threadpool;

public class Singleton {

    // 私有化的構(gòu)造方法,保證外部的類不能通過構(gòu)造器來實例化
    private Singleton() {
    }

    // 靜態(tài)內(nèi)部類只會被加載一次
    // 內(nèi)部類 SingletonHolder 只有在 getInstance() 方法第一次調(diào)用的時候才會被加載(實現(xiàn)了lazy)
    // 而且其加載過程是線程安全的(多線程安全)
    private static class SingletonHolder {
        // 單例變量

        // 常規(guī)寫法
        // private static final Singleton instance = new Singleton();
        
        // 假設(shè)單例對象構(gòu)造方法會拋出異常時的寫法
        private static final Singleton instance;

        static {
            instance = new Singleton();
        }
    }

    // 獲取單例對象實例
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69943.html

相關(guān)文章

  • Java單例模式實現(xiàn)

    摘要:所以,在版本前,雙重檢查鎖形式的單例模式是無法保證線程安全的。 單例模式可能是代碼最少的模式了,但是少不一定意味著簡單,想要用好、用對單例模式,還真得費一番腦筋。本文對Java中常見的單例模式寫法做了一個總結(jié),如有錯漏之處,懇請讀者指正。 餓漢法 顧名思義,餓漢法就是在第一次引用該類的時候就創(chuàng)建對象實例,而不管實際是否需要創(chuàng)建。代碼如下: public class Singleton...

    jaysun 評論0 收藏0
  • 長文慎入-探索Java并發(fā)編程與高并發(fā)解決方案

    摘要:所有示例代碼請見下載于基本概念并發(fā)同時擁有兩個或者多個線程,如果程序在單核處理器上運行多個線程將交替地?fù)Q入或者換出內(nèi)存這些線程是同時存在的,每個線程都處于執(zhí)行過程中的某個狀態(tài),如果運行在多核處理器上此時,程序中的每個線程都 所有示例代碼,請見/下載于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...

    SimpleTriangle 評論0 收藏0
  • 單例模式你會幾種寫法?

    摘要:使用靜態(tài)類體現(xiàn)的是基于對象,而使用單例設(shè)計模式體現(xiàn)的是面向?qū)ο蟆6帉憜卫J降拇a編寫單例模式的代碼其實很簡單,就分了三步將構(gòu)造函數(shù)私有化在類的內(nèi)部創(chuàng)建實例提供獲取唯一實例的方法餓漢式根據(jù)上面的步驟,我們就可以輕松完成創(chuàng)建單例對象了。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 本來打算沒那么快更新的,這陣子在刷Spring的書籍。在看...

    solocoder 評論0 收藏0
  • 并發(fā)編程的藝術(shù)

    摘要:假設(shè)不發(fā)生編譯器重排和指令重排,線程修改了的值,但是修改以后,的值可能還沒有寫回到主存中,那么線程得到就是很自然的事了。同理,線程對于的賦值操作也可能沒有及時刷新到主存中。線程的最后操作與線程發(fā)現(xiàn)線程已經(jīng)結(jié)束同步。 很久沒更新文章了,對隔三差五過來刷更新的讀者說聲抱歉。 關(guān)于 Java 并發(fā)也算是寫了好幾篇文章了,本文將介紹一些比較基礎(chǔ)的內(nèi)容,注意,閱讀本文需要一定的并發(fā)基礎(chǔ)。 本文的...

    curlyCheng 評論0 收藏0

發(fā)表評論

0條評論

HackerShell

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<