日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

不变性真的意味着线程安全吗?

發布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不变性真的意味着线程安全吗? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我經常閱讀有關“如果對象是不可變的,則它是線程安全的”的文章。 實際上,我從未找到過一篇讓我相信不變的意味著線程安全的文章。 即使是Brian Goetz的Java Concurrency in Practice一書中關于不變性的一本書也沒有完全令我滿意。 在這本書中,我們可以在一個框架中逐字閱讀: 不可變對象始終是線程安全的 。 我認為這句話值得更多解釋。

因此,我將嘗試定義不變性及其與線程安全性的關系。

定義 不變性

我的定義是“不可變的對象是在構造之后狀態不會改變的對象”。 我故意含糊其詞,因為沒有人真正同意確切的定義。

線程安全

您可以在Internet上找到許多不同的“線程安全”定義。 定義它實際上非常棘手。 我會說線程安全代碼是在多線程環境中具有預期行為的代碼。 我讓您定義“預期行為”…

字符串示例

讓我們看一下String的代碼(實際上只是一部分代碼……):

public class String {private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0public String(char[] value) {this.value = Arrays.copyOf(value, value.length);}public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;} }

String被認為是不可變的。 看一下它的實現,我們可以推斷出一件事:不可變的對象可以更改其內部狀態(在這種情況下,是延遲加載的哈希碼),只要它在外部不可見即可。

現在,我將以一種非線程安全的方式重寫hashcode方法:

public int hashCode() {if (hash == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {hash = 31 * hash + val[i];}}return hash;}

如您所見,我刪除了局部變量h并直接影響了變量hash 。 此實現不是線程安全的! 如果多個線程同時調用hashcode ,則每個線程的返回值可能不同。 問題是,這堂課是一成不變的嗎? 由于兩個不同的線程可以看到不同的哈希碼,因此從外部角度來看,我們具有狀態更改,因此它不是不可變的。

我們可以得出這樣的結論: String是不可變的, 因為它是線程安全的,而不是相反的。 所以……說“做一些不可變的對象,它是線程安全的!”有什么意義? 但是請注意,您必須使不可變對象具有線程安全性!” ?

ImmutableSimpleDateFormat示例

在下面,我寫了一個類似于SimpleDateFormat的類。

public class VerySimpleDateFormat {private final DateFormat formatter = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT);public String format(Date d){return formatter.format(d);} }

該代碼不是線程安全的,因為SimpleDateFormat.format不是。

這個對象是不變的嗎? 好問題! 我們已盡力使所有字段均不可修改,我們不使用任何設置方法或任何建議對象狀態將改變的方法。 實際上,內部SimpleDateFormat更改其狀態,這就是它不安全線程的原因。 由于對象圖中的某些內容發生了變化,因此即使它看起來像它也不是不變的。問題甚至不是SimpleDateFormat更改其內部狀態,而是它以一種非線程安全的方式進行操作。

總結這個例子,創建一個不可變的類并不容易。 最后一個關鍵字還不夠,您必須確保對象的對象字段不會更改其狀態,這有時是不可能的。

不可變的對象可以具有非線程安全的方法(沒有魔術!)

讓我們看一下下面的代碼。

public class HelloAppender {private final String greeting;public HelloAppender(String name) {this.greeting = 'hello ' + name + '!\n';}public void appendTo(Appendable app) throws IOException {app.append(greeting);} }

HelloAppender類絕對是不可變的。 方法appendTo接受Appendable 。 由于Appendable不能保證是線程安全的(例如StringBuilder ),因此追加到此Appendable會在多線程環境中引起問題。

結論

在某些情況下,創建不可變對象絕對是一個好習慣,并且對創建線程安全代碼有很大幫助。 但是,當我到處閱讀時,這使我感到困擾。 不可變對象是線程安全的 ,顯示為公理。 我明白了這一點,但是我認為對此進行一點思考總是很有益的,以便理解導致非線程安全代碼的原因。

感謝Jose的評論,在本文的結尾我得出了不同的結論。 這都是關于不可變的定義。 需要澄清!

如果滿足以下條件,則對象是不可變的:

  • 它的所有字段在使用之前都已初始化(這意味著您可以進行延遲初始化)
  • 字段的狀態在初始化后不會更改(不更改表示對象圖不會更改,即使子級的內部狀態也是如此)

除非對象必須處理非線程安全的對象,否則不可變對象將始終是線程安全的。

參考: 不變性真的意味著線程安全嗎? 從我們的JCG合作伙伴 Tibo Delor在InvalidCodeException博客中獲得。


翻譯自: https://www.javacodegeeks.com/2012/09/does-immutability-really-means-thread.html

總結

以上是生活随笔為你收集整理的不变性真的意味着线程安全吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。