欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java深入探索線程安全和線程通信的特性

 更新時(shí)間:2022年05月13日 11:02:29   作者:Pretend..  
這篇文章主要介紹了Java線程安全和線程通信的特性,線程安全是多線程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況

一、線程安全(重點(diǎn))

1、線程安全概念

在多線程的情況下,需要考慮多個(gè)線程并行并發(fā)執(zhí)行:此時(shí)多個(gè)線程之間的代碼是隨機(jī)執(zhí)行的。如果多線程環(huán)境下代碼的運(yùn)行結(jié)果是符合我們的預(yù)期的,即在單線程情況下應(yīng)該的結(jié)果,則這個(gè)程序是線程安全的。

2、產(chǎn)生線程不安全的情況

多個(gè)線程共享變量的操作:

  • 都是讀操作時(shí),使用值進(jìn)行判斷,打印等操作(不存在線程安全問題)
  • 存在線程進(jìn)行了寫操作(存在線程安全問題)

3、線程不安全的原因

(1)原子性:多行指令是最小的執(zhí)行單位(不可拆分),就具有原子性。如果不滿足原子性,則存在線程安全問題。

一條java語(yǔ)句不一定是原子的:

  • 如n++、n--,是有三步組成:從內(nèi)存讀取到cpu寄存器、修改數(shù)據(jù)、再寫回到cpu;
  • Object o=new Object(),也涉及到三個(gè)步驟:申請(qǐng)內(nèi)存、初始化對(duì)象、賦值。

以上列舉的雖然只是一條java語(yǔ)句,但是其不具有原子性。

(2)可見性:一個(gè)線程對(duì)共享變量的修改,能夠及時(shí)的被其他線程看見。多個(gè)線程并發(fā)并行執(zhí)行,使用各自的工作內(nèi)存,互相之間不可見(不具有可見性)。

Java內(nèi)存模型(JMM):

目的是屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問差異,以實(shí)現(xiàn)Java程序在各種平臺(tái)下都能達(dá)到一致的并發(fā)效果。

  • 線程之間的共享變量存在主內(nèi)存;
  • 每一個(gè)線程都有自己的工作內(nèi)存;
  • 當(dāng)程序要讀取一個(gè)共享變量時(shí),會(huì)先將變量從主內(nèi)存拷貝到工作內(nèi)存,再?gòu)墓ぷ鲀?nèi)存讀取數(shù)據(jù);
  • 當(dāng)程序要修改一個(gè)共享變量時(shí),會(huì)先修改工作內(nèi)存中的副本,再同步到主內(nèi)存。

(3)代碼順序性/有序性:

代碼重排序:

比如,以下代碼:

1、去前臺(tái)取U盤,

2、回教室寫一會(huì)作業(yè),

3、去前臺(tái)取快遞

在單線程的情況下,JVM、cpu會(huì)對(duì)其進(jìn)行優(yōu)化,1→3→2,這樣會(huì)提高效率,這樣就叫做代碼重排序。

代碼重排序的前提是:保證邏輯不發(fā)生改變。

4、如何解決線程不安全問題

設(shè)計(jì)多線程代碼原則:滿足線程安全的前提下,盡可能地提高效率

(1)對(duì)共享變量的寫操作,可以加鎖來(lái)保證線程安全:

Java中加鎖的兩種方式:

  • synchronized關(guān)鍵字:申請(qǐng)對(duì)給定的Java對(duì)象,對(duì)象頭加鎖;
  • Lock:是一個(gè)鎖的接口,它的實(shí)現(xiàn)類提供了鎖這樣的對(duì)象,可以調(diào)用方法來(lái)加鎖/釋放鎖。

對(duì)共享變量的寫操作,不依賴任何共享變量,也可以使用volatile關(guān)鍵字來(lái)保證線程安全。

(2)對(duì)共享變量的讀操作,使用volatile關(guān)鍵字就可以保證線程安全

volatile關(guān)鍵字:修飾變量,變量的讀操作,本身就保證了原子性,volatile的作用是保證可見性和有序性,這樣就可以保證線程安全。

二、synchronized關(guān)鍵字

synchronized本質(zhì)上是修飾指定對(duì)象的對(duì)象頭去。使用角度來(lái)看,synchronized必須搭配一個(gè)具體的對(duì)象來(lái)使用。

1、使用

(1)修飾普通方法:鎖TestDemo對(duì)象

//方法一
public class TestDemo {
    public synchronized void methond() {
    }
}
//方法二
public class TestDemo {
    public  void methond() {
        synchronized(this){
        }
    }
}

(2)修飾靜態(tài)方法:鎖TestDemo對(duì)象

//方法一
public class TestDemo {
    public synchronized static void method() {
    }
}
//方法二
public class TestDemo {
    public static void method() {
        synchronized(TestDemo.class){
        }
    }
}

2、特性

(1)互斥

synchronized會(huì)起到同步互斥的作用,某個(gè)線程執(zhí)行到某個(gè)對(duì)象的synchronized中時(shí),如果其他線程也執(zhí)行到同一個(gè)對(duì)象synchronized時(shí)會(huì)阻塞等待。

  • 進(jìn)入synchronized修飾的代碼塊,相當(dāng)于加鎖;
  • 退出synchronized代碼塊,相當(dāng)于釋放鎖。

互斥可以滿足原子性,

(2)刷新內(nèi)存

synchronized結(jié)束釋放鎖,會(huì)把工作內(nèi)存中的數(shù)據(jù)刷新到主存中;其他線程申請(qǐng)鎖時(shí),獲取的始終是最新的數(shù)據(jù)。(滿足可見性)。

(3)有序性

某個(gè)線程執(zhí)行一段同步代碼,不管如何重排序,過(guò)程中不可能有其他線程執(zhí)行的指令,這樣多個(gè)線程執(zhí)行同步代碼,就滿足一定的順序。

(4)可重入

同一個(gè)線程,可以多次申請(qǐng)同一個(gè)對(duì)象鎖(可重入)

三、volatile關(guān)鍵字

修飾某個(gè)變量(實(shí)例變量,靜態(tài)變量)

1、保證可見性

代碼在寫入volatilt修飾的變量時(shí):

  • 改變線程工作內(nèi)存中volatile變量副本的值
  • 將改變后的副本的值從工作內(nèi)存中刷新到主存中

代碼在讀取volatile修飾的變量時(shí):

  • 從主存中讀取volatile變量的最新值到工作內(nèi)存中
  • 從工作內(nèi)存中讀取副本值

2、禁止指令重排序

建立內(nèi)存屏障,保證代碼有序性。

3、不保證原子性

synchronized和volatile有著本質(zhì)區(qū)別。synchronized可以保證原子性,volatile保證的是內(nèi)存的可見性。

只能在共享變量的讀操作以及常量賦值操作時(shí)使用(這些操作本身就具有原子性)

四、wait和notify(線程間的通信)

線程通信:線程間通信,就是一個(gè)線程以通知的方式,喚醒某些等待的線程(或者讓當(dāng)前線程等待),這樣就可以讓線程通過(guò)通信的方式具有一定的順序性。

1、wait()方法

wait做的事情:

  • 使當(dāng)前執(zhí)行代碼的線程進(jìn)入等待狀態(tài)(把線程放到等待隊(duì)列中)
  • 釋放當(dāng)前的鎖
  • 滿足一定條件時(shí),重新嘗試獲取這個(gè)鎖

wait結(jié)束等待的條件:

  • 其他線程調(diào)用該對(duì)象的notify方法
  • wait等待時(shí)間超時(shí)(wait提供了一個(gè)帶一個(gè)參數(shù)的方法,可以指定等待時(shí)間)
  • 其他線程調(diào)用該等待線程的interrupted方法,導(dǎo)致wait拋出InterruptedException異常

wait要搭配synchronized來(lái)使用。脫離synchronized使用wait會(huì)直接拋異常。

如下:

Object object = new Object();
    synchronized (object) {
        object.wait();
    }
//這種情況下線程會(huì)一直等待下去,這個(gè)時(shí)候需要使用notify來(lái)喚醒

2、notify()和notifyAll()方法

notify方法只是喚醒某一個(gè)等待的線程,使用notifyAll方法可以一次性喚醒所有的等待線程。

  • notify()也是在同步方法中調(diào)用,用來(lái)通知其他等待的線程,對(duì)其發(fā)出通知notify,并使它們重新獲取該對(duì)象的對(duì)象鎖;
  • 如果有多個(gè)線程在等待,則有線程調(diào)度器隨機(jī)挑選出一個(gè)處于等待狀態(tài)的線程;
  • notify()方法執(zhí)行后,當(dāng)前線程不會(huì)立馬釋放該對(duì)象鎖,要等到當(dāng)前線程將程序執(zhí)行完,退出同步代碼塊后才會(huì)釋放對(duì)象鎖。

【注】

雖然notifyAll()同時(shí)喚醒所有處于等待狀態(tài)的線程,但是這些線程需要競(jìng)爭(zhēng)鎖。所以并不是同時(shí)執(zhí)行,仍然是有先后順序的執(zhí)行。

3、wait和sleep的對(duì)比

一個(gè)是用于線程之間的通信,一個(gè)是讓線程阻塞一段時(shí)間。

  • wait需要搭配synchrionzed使用,sleep不用
  • wait是Object的方法,sleep是Thread的靜態(tài)方法

五、線程和進(jìn)程的比較

1、線程的優(yōu)點(diǎn)

  1. 創(chuàng)建線程的代價(jià)比創(chuàng)建進(jìn)程小得多
  2. 與進(jìn)程切換相比,線程切換需要操作系統(tǒng)做的事少得多
  3. 線程占用的資源比進(jìn)程少
  4. 能充分利用多個(gè)處理器,提高效率
  5. 在等待I/O操作結(jié)束的同時(shí),程序可執(zhí)行其他的計(jì)算任務(wù)
  6. I/O密集型操作,為了提高性能,將I/O操作重疊。線程可以同時(shí)等待不同的I/O操作
  7. 計(jì)算密集型應(yīng)用,為了能在多處理器系統(tǒng)上運(yùn)行,將計(jì)算分解到多個(gè)線程中實(shí)現(xiàn)

2、線程和進(jìn)程的區(qū)別

  • 進(jìn)程是進(jìn)行資源分配的最小單位,線程是程序執(zhí)行的最小單位
  • 進(jìn)程有自己的內(nèi)存地址空間,線程只獨(dú)享指令流執(zhí)行的必要資源,如寄存器和棧
  • 同一個(gè)進(jìn)程的各線程之間共享內(nèi)存和文件資源,可以不通過(guò)內(nèi)核進(jìn)行直接通信
  • 線程的創(chuàng)建、切換、銷毀效率更高

到此這篇關(guān)于Java深入探索線程安全和線程通信的特性的文章就介紹到這了,更多相關(guān)Java線程安全內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java異常類型介紹及處理方法

    Java異常類型介紹及處理方法

    這篇文章介紹了Java異常類型介紹及處理方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目的過(guò)程詳解

    Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目的過(guò)程詳解

    這篇文章主要介紹了Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • Java常用類之字符串相關(guān)類使用詳解

    Java常用類之字符串相關(guān)類使用詳解

    String、StringBuilder、StringBuffer類是Java中常用的三個(gè)字符串相關(guān)類。本文將通過(guò)示例為大家講解一下他們的用法,需要的可以參考一下
    2022-08-08
  • 解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問題

    解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問題

    這篇文章主要介紹了mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問題的解決方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • web 容器的設(shè)計(jì)如何實(shí)現(xiàn)

    web 容器的設(shè)計(jì)如何實(shí)現(xiàn)

    這篇文章主要介紹了web 容器的設(shè)計(jì)如何實(shí)現(xiàn)的相關(guān)資料,本文旨在介紹如何設(shè)計(jì)一個(gè)web容器,只探討實(shí)現(xiàn)的思路,并不涉及過(guò)多的具體實(shí)現(xiàn)。把它分解劃分成若干模塊和組件,每個(gè)組件模塊負(fù)責(zé)不同的功能,需要的朋友可以參考下
    2016-12-12
  • java 取交集方法retainAll的實(shí)現(xiàn)

    java 取交集方法retainAll的實(shí)現(xiàn)

    這篇文章主要介紹了java 取交集方法retainAll的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java多線程的用法詳細(xì)介紹

    Java多線程的用法詳細(xì)介紹

    這篇文章主要介紹了Java多線程的用法詳細(xì)介紹的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Spring?Security放行的接口Knife4j靜態(tài)資源的問題小結(jié)

    Spring?Security放行的接口Knife4j靜態(tài)資源的問題小結(jié)

    這篇文章主要介紹了Spring?Security使用Knife4j靜態(tài)資源的問題小結(jié),項(xiàng)目中使用?Spring?Security?做身份認(rèn)證和授權(quán),使用?Knife4j?做接口調(diào)試,需要?Spring?Security?放行的接口記錄在?RequestMatcherConstant?類中,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Spring的初始化前中后詳細(xì)解讀

    Spring的初始化前中后詳細(xì)解讀

    這篇文章主要介紹了Spring的初始化前中后詳細(xì)解讀,Spring?框架是一個(gè)非常流行的?Java?框架,它提供了一種輕量級(jí)的、可擴(kuò)展的方式來(lái)構(gòu)建企業(yè)級(jí)應(yīng)用程序,在?Spring?的生命周期中,有三個(gè)重要的階段,即初始化前、初始化、初始化后,需要的朋友可以參考下
    2023-09-09
  • 詳解Spring Boot中使用@Scheduled創(chuàng)建定時(shí)任務(wù)

    詳解Spring Boot中使用@Scheduled創(chuàng)建定時(shí)任務(wù)

    本篇文章中主要介紹了Spring Boot中使用@Scheduled創(chuàng)建定時(shí)任務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03

最新評(píng)論