成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java多線程基礎(chǔ)(二)——Java內(nèi)存模型

huhud / 1866人閱讀

摘要:一主存儲器與工作存儲器內(nèi)存模型分為主存儲器和工作存儲器兩種。工作存儲器每個線程各自獨立所擁有的作業(yè)區(qū),在中,存有中的部分拷貝,稱之為工作拷貝。注意線程欲退出時,不會執(zhí)行工作存儲器的釋放操作。

一、主存儲器與工作存儲器

Java內(nèi)存模型(memory model)分為主存儲器(main memory)和工作存儲器(working memory)兩種。

主存儲器(main memory):
類的實例所存在的區(qū)域,main memory為所有的線程所共享。

工作存儲器(working memory):
每個線程各自獨立所擁有的作業(yè)區(qū),在working memory中,存有main memory中的部分拷貝,稱之為工作拷貝(working copy)。

二、字段的使用 2.1 字段的引用

線程無法直接對主存儲器進行操作,當線程需要引用實例的字段的值時,會一次將字段值從主存儲器拷貝到工作存儲器上(相當于上圖中的read->load)。
當線程再次需要引用相同的字段時,可能直接使用剛才的工作拷貝(use),也可能重新從主存儲器獲?。╮ead->load->use)。
具體會出現(xiàn)哪種情況,由JVM決定。

2.2 字段的賦值

由于線程無法直接對主存儲器進行操作,所以也就無法直接將值指定給字段。
當線程欲將值指定給字段時,會一次將值指定給位于工作存儲器上的工作拷貝(assign),指定完成后,工作拷貝的內(nèi)容便會復(fù)制到主存儲器(store->write),至于何時進行復(fù)制,由JVM決定。
因此,當線程反復(fù)對一個實例的字段進行賦值時,可能只會對工作拷貝進行指定(assign),此時只有指定的最后結(jié)果會在某個時刻拷貝到主存儲器(store-write);也可能在每次指定時,都進行拷貝到主存儲器的操作(assign->store->write)。

三、線程的原子操作

Java語言規(guī)范定義了線程的六種原子操作:

read
負責(zé)從主存儲器(main memory)拷貝到工作存儲器(working memory)

write
與上述相反,負責(zé)從工作存儲器(working memory)拷貝到主存儲器(main memory)

use
表示線程引用工作存儲器(working memory)的值

assign
表示線程將值指定給工作存儲器(working memory)

lock
表示線程取得鎖定

unlock
表示線程解除鎖定

四、synchronied的本質(zhì) 4.1 線程欲進入synchronized

線程欲進入synchronized時,會執(zhí)行以下兩類操作:

強制寫入主存儲器(main memory)

當線程欲進入synchronized時,如果該線程的工作存儲器(working memory)上有未映像到主存儲器的拷貝,則這些內(nèi)容會強制寫入主存儲器(store->write),則這些計算結(jié)果就會對其它線程可見(visible)。

工作存儲器(working memory)的釋放

當線程欲進入synchronized時,工作存儲器上的工作拷貝會被全部丟棄。之后,欲引用主存儲器上的值的線程,必定會從主存儲器將值拷貝到工作拷貝(read->load)。

4.2 線程欲退出synchronized

線程欲退出synchronized時,會執(zhí)行以下操作:

強制寫入主存儲器(main memory)

當線程欲退出synchronized時,如果該線程的工作存儲器(working memory)上有未映像到主存儲器的拷貝,則這些內(nèi)容會強制寫入主存儲器(store->write),則這些計算結(jié)果就會對其它線程可見(visible)。

注意: 線程欲退出synchronized時,不會執(zhí)行工作存儲器(working memory)的釋放 操作。

五、volatile的本質(zhì)

volatile具有以下兩種功能:

進行內(nèi)存同步

volatile只能做內(nèi)存同步,不能取代synchronized關(guān)鍵字做線程同步。
當線程欲引用volatile字段的值時,通常都會發(fā)生從主存儲器到工作存儲器的拷貝操作;相反的,將值指定給寫著volatile的字段后,工作存儲器的內(nèi)容通常會立即映像到主存儲器

以原子(atomic)方式進行l(wèi)ong、double的指定

六、Double Checked Locking Pattern的危險性 6.1 可能存在缺陷的單例模式

設(shè)計模式中有一種單例模式(Singleton Pattern),通常采用鎖來保證線程的安全性。

Main類:

//兩個Main線程同時調(diào)用單例方法getInstance
public class Main extends Thread {
    public static void main(String[] args) {
        new Main().start();
        new Main().start();
    }
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":" + MySystem.getInstance().getDate());
    }
}

單例類:

//采用延遲加載+雙重鎖的形式保證線程安全以及性能
public class MySystem {
    private static MySystem instance = null;
    private Date date = new Date();
?
    private MySystem() {
    }
    public Date getDate() {
        return date;
    }
    public static MySystem getInstance() {
        if (instance == null) {
            synchronized (MySystem.class) {
                if (instance == null) {
                    instance = new MySystem();
                }
            }
        }
        return instance;
    }
}

分析:
上述Main類的MySystem.getInstance().getDate()調(diào)用可能返回null或其它值。
假設(shè)有兩個線程A和B,按照以下順序執(zhí)行:

當線程A執(zhí)行完A-4且未退出synchronized時,線程B開始執(zhí)行,此時B獲得了A創(chuàng)建好的instance實例。
但是注意,此時instance實例可能并未完全初始化完成。
這是因為線程A制作MySystem實例時,會給date字段指定值new Date(),此時可能只完成了assign操作(線程A對工作存取器上的工作拷貝進行指定),在線程A退出synchronized時,線程A的工作存儲器上的值不保證一定會映像到主存儲器上(store->write)。

所以,當線程B在線程A退出前就調(diào)用MySystem.getInstance().getDate()方法的話,由于主存儲器上的date字段并未被賦值過,所以B得到的date字段就是未初始化過的。

注意:上面描述的這種情況是否真的會發(fā)生,取決于JVM,由Java語言規(guī)范決定。

解決方法:
采用懶加載模式,在MySystem類中直接為instance 字段賦值:
private static MySystem instance = new MySystem();

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71490.html

相關(guān)文章

  • 深入理解Java內(nèi)存模型(一)——基礎(chǔ)

    摘要:線程之間的通信由內(nèi)存模型本文簡稱為控制,決定一個線程對共享變量的寫入何時對另一個線程可見。為了保證內(nèi)存可見性,編譯器在生成指令序列的適當位置會插入內(nèi)存屏障指令來禁止特定類型的處理器重排序。 并發(fā)編程模型的分類 在并發(fā)編程中,我們需要處理兩個關(guān)鍵問題:線程之間如何通信及線程之間如何同步(這里的線程是指并發(fā)執(zhí)行的活動實體)。通信是指線程之間以何種機制來交換信息。在命令式編程中,線程之間的...

    jsdt 評論0 收藏0
  • 深入理解Java內(nèi)存模型)——重排序

    摘要:前情提要深入理解內(nèi)存模型一基礎(chǔ)編譯器運行時會對指令進行重排序。以處理器的猜測執(zhí)行為例,執(zhí)行線程的處理器可以提前讀取并計算,然后把計算結(jié)果臨時保存到一個名為重排序緩沖的硬件緩存中。請看下篇深入理解內(nèi)存模型三順序一致性 前情提要 深入理解Java內(nèi)存模型(一)——基礎(chǔ) Java編譯器、運行時會對指令進行重排序。這種重排序在單線程和多線程情況下分別有什么影響呢? 數(shù)據(jù)依賴性 如果兩個操...

    tunny 評論0 收藏0
  • Java面試 32個核心必考點完全解析

    摘要:如問到是否使用某框架,實際是是問該框架的使用場景,有什么特點,和同類可框架對比一系列的問題。這兩個方向的區(qū)分點在于工作方向的側(cè)重點不同。 [TOC] 這是一份來自嗶哩嗶哩的Java面試Java面試 32個核心必考點完全解析(完) 課程預(yù)習(xí) 1.1 課程內(nèi)容分為三個模塊 基礎(chǔ)模塊: 技術(shù)崗位與面試 計算機基礎(chǔ) JVM原理 多線程 設(shè)計模式 數(shù)據(jù)結(jié)構(gòu)與算法 應(yīng)用模塊: 常用工具集 ...

    JiaXinYi 評論0 收藏0
  • Week 1 - Java 線程 - Java 內(nèi)存模型

    摘要:目的是解決由于多線程通過共享內(nèi)存進行通信時,存在的原子性可見性緩存一致性以及有序性問題。最多只有一個線程能持有鎖。線程加入規(guī)則對象的結(jié)束先行發(fā)生于方法返回。 前言 學(xué)習(xí)情況記錄 時間:week 1 SMART子目標 :Java 多線程 學(xué)習(xí)Java多線程,要了解多線程可能出現(xiàn)的并發(fā)現(xiàn)象,了解Java內(nèi)存模型的知識是必不可少的。 對學(xué)習(xí)到的重要知識點進行的記錄。 注:這里提到的是Ja...

    zhaofeihao 評論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會遇到兩個主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    mtunique 評論0 收藏0

發(fā)表評論

0條評論

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