java中的final關鍵字,java final 內存語義_final 域的內存語義

 2023-11-19 阅读 28 评论 0

摘要:眾所周知,final 關鍵字在Java語法中用來修飾常亮,不允許修改的數據。那么對于前面提到的volatile 類型的數據相比,除了不能被修改好像對final的寫和讀和普通的變量并沒有什么不同,那么筆者將在這里簡單概述下final的內存語義以及其實現的意義。1、

眾所周知,final 關鍵字在Java語法中用來修飾常亮,不允許修改的數據。那么對于前面提到的volatile 類型的數據相比,除了不能被修改好像對final的寫和讀和普通的變量并沒有什么不同,那么筆者將在這里簡單概述下final的內存語義以及其實現的意義。

1、重排序規則

java中的final關鍵字、?在構造函數內對一個final域的寫入,與隨后吧這個被構造的對象賦值給一個引用變量,這兩個操作之后不能重排序

初次讀一個包含final域的對象,與隨后初次讀這個這個對象的final域,兩者之間不能重排序(針對特殊處理器)

首先看下面一段代碼

java中的域是什么意思。static class FinalWriteExample {int a;final int b;static FinalWriteExample example;public FinalWriteExample(int a, int b) {this.b = b; //1. 對final域寫入this.a = a; //2. 對普通域寫入}public static void write() {example = new FinalWriteExample(1, 2); // 3.將構造的對象賦值給一個引用變量}public static void read() {FinalWriteExample exampleObj = example;int exampleA = exampleObj.a;int exampleB = exampleObj.b;}}

上面的代碼示例中,就是一個非常簡單的程序,根據第一條重排序規則要求:構造函數中,第一次對final域的寫入(操作 1)和將構造函數賦值給一個引用變量(操作 3)之間不能重排序。

試想一下:倘若沒有這個要求,操作1->2->3 可能會被重排序為 2->3->1 那么當其他線程嘗試對其這個變量的時候,final域可能還沒有完成初始化,由于類的加載器有初始化的步驟,那么b的值將會是0,其后執行操作1,此時final的值又被更新為1。可以看到出現了一個非常嚴重的缺陷:?線程看到的final域的值可能會變,這與final的作用相違背。?為了修復這個漏洞 JSR-133 增強了final的語義,在第一次對final域賦值,與將構造的對象賦值給其他引用之間增加StoreStore 內存屏障指令,禁止重排序。

javaweb域對象?上面的final域的類型是基本類型,倘若是引用類型的話,那么第一條重排序規則可以這樣匯總: 構造函數中,第一次對final的寫入、對final域的成員變量寫入以及將構造的對象賦值給引用變量,三者之間不能出現重排序。

同樣的,對于final域的讀操作也有重排序要求: 在一個線程中,初次讀對象引用與初次讀這個對象引用的final域,兩者之間不能重排序。但是因為這兩者之間有依賴關系,大部分處理器不會進行重排序,所以這個規則只針對一些特殊的處理器。

2、引用提前"溢出"

java修改域用戶。盡管JMM要求了重排序規則,但是一些特殊的代碼還是能夠將對象引用在構造方法執行完成之前溢出,修改章節1 的代碼,如下:

static class FinalWriteExample {int a;final int b;static FinalWriteExample example;public FinalWriteExample(int a, int b) {FinalWriteExample.example = this; // 4.this引用被提前溢出this.b = b; //1. 對final域寫入this.a = a; //2. 對普通域寫入}public static void write() {example = new FinalWriteExample(1, 2); // 3.將構造的對象賦值給一個引用變量}}

操作4 在構造方法未完成之前就完成了引用賦值,倘若其他線程在讀取example變量,那么也會出現fianl變量會變的問題,所以在多線程的編程中,我們要盡量避免在構造方法完成之前引用溢出的問題。

java final方法,3、總結

綜上所述,我們可以知道在針對 final的操作中,我們的目的主要是確保 final域在構造方法賦值之前被成功的正確的初始化。只要對象被正確的構造初始化,那么我們就不必使用同步操作就可以使得其他線程正確的讀取到final的值。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/182826.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息