亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

如何使用 volatile, synchronized, final 進(jìn)行線程間通信

keithxiaoy / 697人閱讀

摘要:如線程執(zhí)行后,線程執(zhí)行,相當(dāng)于線程向線程發(fā)送了消息。我們可以利用這種互斥性來進(jìn)行線程間通信。

你是否真正理解并會(huì)用volatile, synchronized, final進(jìn)行線程間通信呢,如果你不能回答下面的幾個(gè)問題,那就說明你并沒有真正的理解:

對(duì)volatile變量的操作一定具有原子性嗎?

synchronized所謂的加鎖,鎖住的是什么?

final定義的變量不變的到底是什么?

java內(nèi)存模型 內(nèi)存模型

看java內(nèi)存模型之前,我們先來看看什么是內(nèi)存模型?

在多處理器系統(tǒng)中,處理器通常有多級(jí)緩存,因?yàn)檫@些緩存離處理器更近并且可以存儲(chǔ)一部分?jǐn)?shù)據(jù),所以緩存可以改善處理器獲取數(shù)據(jù)的速度和減少對(duì)共享內(nèi)存數(shù)據(jù)總線的占用。緩存雖然能極大的提高性能,但是同時(shí)也帶來了諸多挑戰(zhàn)。例如,當(dāng)兩個(gè)處理器同時(shí)操作同一個(gè)內(nèi)存地址的時(shí)候,該如何處理?這兩個(gè)處理器在什么條件下才能看到相同的值?

對(duì)于處理器而言,一個(gè)內(nèi)存模型就是定義一些充分必要的規(guī)范,這些規(guī)范使得其他處理器對(duì)內(nèi)存的寫操作對(duì)當(dāng)前處理器可見,或者當(dāng)前處理器的寫操作對(duì)其他處理器可見。

其他處理器對(duì)內(nèi)存的寫一定發(fā)生在當(dāng)前處理器對(duì)同一內(nèi)存的讀之前,稱之為其他處理器對(duì)內(nèi)存的寫對(duì)當(dāng)前處理器可見。
Java 內(nèi)存模型

知道了內(nèi)存模型,那么應(yīng)該可以更好的理解java內(nèi)存模型。

簡(jiǎn)單的講,java內(nèi)存模型指的就是一套規(guī)范,現(xiàn)在最新的規(guī)范為JSR-133。這套規(guī)范包含:

線程之間如何通過內(nèi)存通信

線程之間通過什么方式通信才合法,才能得到期望的結(jié)果。

Java 內(nèi)存模型中的內(nèi)存結(jié)構(gòu)

我們已經(jīng)知道 java 內(nèi)存模型就是一套規(guī)范,那么在這套規(guī)范中,規(guī)定的內(nèi)存結(jié)構(gòu)是什么樣的呢?

簡(jiǎn)單的講,Java 內(nèi)存模型將內(nèi)存分為共享內(nèi)存和本地內(nèi)存。共享內(nèi)存又稱為堆內(nèi)存,指的就是線程之間共享的內(nèi)存,包含所有的實(shí)例域、靜態(tài)域和數(shù)組元素。每個(gè)線程都有一個(gè)私有的,只對(duì)自己可見的內(nèi)存,稱之為本地內(nèi)存。

java內(nèi)存模型中的內(nèi)存結(jié)構(gòu)如下圖所示:

共享內(nèi)存中共享變量雖然由所有的線程共享,但是為了提高效率,線程并不直接使用這些變量,每個(gè)線程都會(huì)在自己的本地內(nèi)存中存儲(chǔ)一個(gè)共享內(nèi)存的副本,使用這個(gè)副本參與運(yùn)算。由于這個(gè)副本的參與,導(dǎo)致了線程之間對(duì)共享內(nèi)存的讀寫存在可見性問題。

為了方便線程之間的通信,java 提供了 volatile, synchronized, final 三個(gè)關(guān)鍵字供我們使用,下面我們來看看如何使用它們進(jìn)行線程間通信

volatile

volatile 定義的變量,特殊性在于:

一個(gè)線程對(duì) volatile 變量的寫一定對(duì)之后對(duì)這個(gè)變量的讀的線程可見。

等價(jià)于

一個(gè)線程對(duì) volatile 變量的讀一定能看見在它之前最后一個(gè)線程對(duì)這個(gè)變量的寫。

為了實(shí)現(xiàn)這些語(yǔ)義,Java 規(guī)定,(1)當(dāng)一個(gè)線程要使用共享內(nèi)存中的 volatile 變量時(shí),如圖中的變量a,它會(huì)直接從主內(nèi)存中讀取,而不使用自己本地內(nèi)存中的副本。(2)當(dāng)一個(gè)線程對(duì)一個(gè) volatile 變量進(jìn)行寫時(shí),它會(huì)將這個(gè)共享變量的值刷新到共享內(nèi)存中。

我們可以看到,其實(shí) volatile 變量保證的是一個(gè)線程對(duì)它的寫會(huì)立即刷新到主內(nèi)存中,并置其它線程的副本為無效,它并不保證對(duì) volatile 變量的操作都是具有原子性的。

由于

 public void add(){
     a++;         #1
 } 

等價(jià)于

 public void add() {
    temp = a;        
    temp = temp +1;  
    a = temp;         
 } 

代碼1并不是一個(gè)原子操作,所以類似于 a++ 這樣的操作會(huì)導(dǎo)致并發(fā)數(shù)據(jù)問題。

volatile 變量的寫可以被之后其他線程的讀看到,因此我們可以利用它進(jìn)行線程間的通信。如

volatile int a;

public void set(int b) {
    a = b; 
}

public void get() {
    int i = a; 
}

線程A執(zhí)行set()后,線程B執(zhí)行g(shù)et(),相當(dāng)于線程A向線程B發(fā)送了消息。

synchronized

如果我們非要使用 a++ 這種復(fù)合操作進(jìn)行線程間通信呢?java 為我們提供了synchronized。

 public synchronized void add() {
    a++; 
 }

synchronized 使得

它作用范圍內(nèi)的代碼對(duì)于不同線程是互斥的,并且線程在釋放鎖的時(shí)候會(huì)將共享變量的值刷新到共享內(nèi)存中。

我們可以利用這種互斥性來進(jìn)行線程間通信??聪旅娴拇a,

public synchronized void add() {
    a++; 
}

public synchronized void get() {
    int i = a; 
}

當(dāng)線程A執(zhí)行 add(),線程B調(diào)用get(),由于互斥性,線程A執(zhí)行完add()后,線程B才能開始執(zhí)行g(shù)et(),并且線程A執(zhí)行完add(),釋放鎖的時(shí)候,會(huì)將a的值刷新到共享內(nèi)存中。因此線程B拿到的a的值是線程A更新之后的。

volatile 和 synchronized比較

根據(jù)以上的分析,我們可以發(fā)現(xiàn)volatile和synchronized有些相似。

當(dāng)線程對(duì) volatile變量寫時(shí),java 會(huì)把值刷新到共享內(nèi)存中;而對(duì)于synchronized,指的是當(dāng)線程釋放鎖的時(shí)候,會(huì)將共享變量的值刷新到主內(nèi)存中。

線程讀取volatile變量時(shí),會(huì)將本地內(nèi)存中的共享變量置為無效;對(duì)于synchronized來說,當(dāng)線程獲取鎖時(shí),會(huì)將當(dāng)前線程本地內(nèi)存中的共享變量置為無效。

synchronized 擴(kuò)大了可見影響的范圍,擴(kuò)大到了synchronized作用的代碼塊。

final 變量

final關(guān)鍵字可以作用于變量、方法和類,我們這里只看final 變量。

final變量的特殊之處在于,

final 變量一經(jīng)初始化,就不能改變其值。

這里的值對(duì)于一個(gè)對(duì)象或者數(shù)組來說指的是這個(gè)對(duì)象或者數(shù)組的引用地址。因此,一個(gè)線程定義了一個(gè)final變量之后,其他任意線程都拿到這個(gè)變量。但有一點(diǎn)需要注意的是,當(dāng)這個(gè)final變量為對(duì)象或者數(shù)組時(shí),

雖然我們不能講這個(gè)變量賦值為其他對(duì)象或者數(shù)組,但是我們可以改變對(duì)象的域或者數(shù)組中的元素。

線程對(duì)這個(gè)對(duì)象變量的域或者數(shù)據(jù)的元素的改變不具有線程可見性。

總結(jié)

有時(shí)候,我們?cè)趯W(xué)習(xí)一門技術(shù)過程中,并不能僅僅局限于怎么用,知道怎么用之后,我們應(yīng)該深入的探究一下,為什么這么用之后就能得到我們想要的結(jié)果呢?既要知其然,更要知其所以然。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/65519.html

相關(guān)文章

  • Java內(nèi)存模型

    摘要:內(nèi)存模型對(duì)內(nèi)存模型的介紹對(duì)內(nèi)存模型的結(jié)構(gòu)圖的線程之間的通信是通過共享內(nèi)存的方式進(jìn)行隱式通信,即線程把某狀態(tài)寫入主內(nèi)存中的共享變量,線程讀取的值,這樣就完成了通信。 Java內(nèi)存模型(JMM) 1.對(duì)內(nèi)存模型的介紹 ①對(duì)Java內(nèi)存模型的結(jié)構(gòu)圖 java的線程之間的通信是通過共享內(nèi)存的方式進(jìn)行隱式通信,即線程A把某狀態(tài)寫入主內(nèi)存中的共享變量X,線程B讀取X的值,這樣就完成了通信。是一種...

    sherlock221 評(píng)論0 收藏0
  • 并發(fā)編程基礎(chǔ)知識(shí)二

    摘要:進(jìn)入方法線程停止關(guān)鍵字雖然擁有多個(gè)線程之間的可見性,但是卻不具備原子性關(guān)鍵字用于針對(duì)多個(gè)線程可變的變量操作,但是不能替代關(guān)鍵字的同步功能。 volatile關(guān)鍵字的作用是變量在多個(gè)線程之間可見volatile的作用是強(qiáng)制線程到主內(nèi)存(共享內(nèi)存)里讀取變量,而不是線程工作內(nèi)存區(qū)里去讀取變量,從而實(shí)現(xiàn)了多個(gè)線程之間的變量可見,也就是滿足線程安全的可見性。 private volat...

    CKJOKER 評(píng)論0 收藏0
  • 慕課網(wǎng)_《細(xì)說Java多線程之內(nèi)存可見性》學(xué)習(xí)總結(jié)

    時(shí)間:2017年07月09日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:無學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程簡(jiǎn)介 1-1 課程簡(jiǎn)介 課程目標(biāo)和學(xué)習(xí)內(nèi)容 共享變量在線程間的可見性 synchronized實(shí)現(xiàn)可見性 volatile實(shí)現(xiàn)可見性 指令重排序 as-if-seria...

    wupengyu 評(píng)論0 收藏0
  • bat等大公司??糺ava多線程面試題

    摘要:典型地,和被用在等待另一個(gè)線程產(chǎn)生的結(jié)果的情形測(cè)試發(fā)現(xiàn)結(jié)果還沒有產(chǎn)生后,讓線程阻塞,另一個(gè)線程產(chǎn)生了結(jié)果后,調(diào)用使其恢復(fù)。使當(dāng)前線程放棄當(dāng)前已經(jīng)分得的時(shí)間,但不使當(dāng)前線程阻塞,即線程仍處于可執(zhí)行狀態(tài),隨時(shí)可能再次分得時(shí)間。 1、說說進(jìn)程,線程,協(xié)程之間的區(qū)別 簡(jiǎn)而言之,進(jìn)程是程序運(yùn)行和資源分配的基本單位,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元...

    Charlie_Jade 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<