亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一、線程安全(重點)

1、線程安全概念

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

2、產生線程不安全的情況

多個線程共享變量的操作:

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

3、線程不安全的原因

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

一條java語句不一定是原子的:

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

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

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

Java內存模型(JMM):

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

  • 線程之間的共享變量存在主內存;
  • 每一個線程都有自己的工作內存;
  • 當程序要讀取一個共享變量時,會先將變量從主內存拷貝到工作內存,再從工作內存讀取數據;
  • 當程序要修改一個共享變量時,會先修改工作內存中的副本,再同步到主內存。

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

代碼重排序:

比如,以下代碼:

1、去前臺取U盤,

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

3、去前臺取快遞

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

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

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

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

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

Java中加鎖的兩種方式:

  • synchronized關鍵字:申請對給定的Java對象,對象頭加鎖;
  • Lock:是一個鎖的接口,它的實現類提供了鎖這樣的對象,可以調用方法來加鎖/釋放鎖。

對共享變量的寫操作,不依賴任何共享變量,也可以使用volatile關鍵字來保證線程安全。

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

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

二、synchronized關鍵字

synchronized本質上是修飾指定對象的對象頭去。使用角度來看,synchronized必須搭配一個具體的對象來使用。

1、使用

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

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

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

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

2、特性

(1)互斥

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

  • 進入synchronized修飾的代碼塊,相當于加鎖;
  • 退出synchronized代碼塊,相當于釋放鎖。

互斥可以滿足原子性,

(2)刷新內存

synchronized結束釋放鎖,會把工作內存中的數據刷新到主存中;其他線程申請鎖時,獲取的始終是最新的數據。(滿足可見性)。

(3)有序性

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

(4)可重入

同一個線程,可以多次申請同一個對象鎖(可重入)

三、volatile關鍵字

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

1、保證可見性

代碼在寫入volatilt修飾的變量時:

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

代碼在讀取volatile修飾的變量時:

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

2、禁止指令重排序

建立內存屏障,保證代碼有序性。

3、不保證原子性

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

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

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

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

1、wait()方法

wait做的事情:

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

wait結束等待的條件:

  • 其他線程調用該對象的notify方法
  • wait等待時間超時(wait提供了一個帶一個參數的方法,可以指定等待時間)
  • 其他線程調用該等待線程的interrupted方法,導致wait拋出InterruptedException異常

wait要搭配synchronized來使用。脫離synchronized使用wait會直接拋異常。

如下:

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

2、notify()和notifyAll()方法

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

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

【注】

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

3、wait和sleep的對比

一個是用于線程之間的通信,一個是讓線程阻塞一段時間。

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

五、線程和進程的比較

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

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

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

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

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

相關文章

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

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

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

    Jvisualvm監(jiān)控遠程SpringBoot項目的過程詳解

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

    Java常用類之字符串相關類使用詳解

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

    解決mybatis使用char類型字段查詢oracle數據庫時結果返回null問題

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

    web 容器的設計如何實現

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

    java 取交集方法retainAll的實現

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

    Java多線程的用法詳細介紹

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

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

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

    Spring的初始化前中后詳細解讀

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

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

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

最新評論