不變性真的意味著線程安全嗎?

我經常閱讀有關“如果對象是不可變的,則它是線程安全的”的文章。 實際上,我從未找到過一篇讓我相信不變的意味著線程安全的文章。 即使是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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371525.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371525.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371525.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言設計 數組的知識點,C語言程序設計知識點及示例.pdf

C語言程序設計知識點及示例四川大學錦江學院C語言程序設計知識點及示例知識點1&#xff1a;除了復合語句而外&#xff0c;C語言的語句都以分號結束。示例1&#xff1a;C語言的簡單語句 (非復合語句語句)必須以 結束。參考答案&#xff1a;分號知識點2&#xff1a;目標程序和可執…

移動端知識匯總

參見地址: https://github.com/jtyjty99999/mobileTech 轉載于:https://www.cnblogs.com/duanyue/p/7337789.html

在移動端設置overflow:hidden禁止滾動的解決方法

如果你是將overflow:hidden用在了body上那么不管用&#xff0c;因為移動端是基于touch事件。 兩種解決方法&#xff1a; 1、為html和body同時設置height:100%;overflow:hidden; html, body{height:100%;overflow:hidden; }2、使用touchmove $(document).on(touchmove,function …

單元測試線程代碼的5個技巧

這是一些技巧&#xff0c;說明如何進行代碼的邏輯正確性測試&#xff08;與多線程正確性相對&#xff09;。 我發現本質上有兩種帶有線程代碼的刻板印象模式&#xff1a; 面向任務–許多短期運行的同類任務&#xff0c;通常在Java 5執行程序框架內運行&#xff0c; 面向流程–…

jsp2

D:\Software\Tomcat7\work\Catalina\localhost 是緩存目錄&#xff0c;可以刪掉隱藏域&#xff1a;頁面表單中的一個元素&#xff0c;跟文本框一樣&#xff0c;但是用戶看不到1.建立test1--form表單需要它&#xff0c;而不需要用戶看到&#xff0c;用隱藏域<body><%re…

MongoDB MapReduce 的示例。

// JavaScript source code db.runCommand({mapreduce: "page",map: function Map() {emit(this.title, // how to group{ name: this.name } // associated data point (document));},reduce: function Reduce(key, values) {//reduce用來處理group出來是多條數…

c語言長空格的代碼是什么,c語言中表示空格的是什么代碼?

分析如下&#xff1a;不是所有字符都需要轉義的&#xff0c;空格直接就敲空格&#xff0c;或者使用ASCII碼值賦值為32。空格沒有轉義字符。合法轉義字符如下&#xff1a;\a 響鈴(BEL) 、\b 退格(BS)、\f 換頁(FF)、\n 換行(LF)、\r 回車(CR)、\t 水平制表(HT)、\v 垂直制表(VT)…

使用NoSQL實現實體服務–第1部分:概述

在過去的幾周中&#xff0c;我一直在進行一些研發工作&#xff0c;以了解使用NoSQL數據庫實現實體服務 &#xff08;也稱為數據服務&#xff09;的優勢。 實體服務是托馬斯埃爾&#xff08;Thomas Erl&#xff09;的《服務技術》叢書中提出的服務分類。 它用于描述高度不可知和…

IO注意事項

read()方法返回值為什么是int? 因為字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111,那么這11111111是byte類型的-1,我們的程序是遇到-1就會停止不讀了,后面的數據就讀不…

c語言用星號輸出沙漏,《算法筆記》學習日記——3.3 圖形輸出

3.3 圖形輸出問題 A: 輸出梯形題目描述輸入一個高度h&#xff0c;輸出一個高為h&#xff0c;上底邊為h的梯形。輸入一個整數h(1<h<1000)。輸出h所對應的梯形。樣例輸入web5樣例輸出數組*********************************************思路這一類的題目都比較簡單&#xf…

JavaOne 2012:101種改進Java的方法-開發人員參與為何如此重要

Bruno Souza &#xff0c; Martijn Verburg和Heather Vancura在希爾頓酒店的大陸宴會廳4中展示了“ 101種改進Java的方法&#xff1a;開發人員參與為何如此重要”。 他們將其分為自己最熟悉的領域。 SouJava的創始人兼協調員 Souza談到了通過用戶組的更大參與。 Verberg也在倫敦…

Java組合實體模式~

組合實體模式用于EJB持久化機制。 組合實體是表示對象圖的EJB實體bean。 當組合實體更新時&#xff0c;內部依賴對象bean將自動更新為由EJB實體bean管理。 以下是組合實體Bean的參與者。 組合實體 - 它是主要的實體bean。 它可以是粗粒度的或可以包含用于持久性目的的粗粒度對象…

python中的一些小知識

在最近學習python中遇到的一些小問題匯總一下&#xff1a; 1.在windows7下安裝python3.5版本時提示安裝不了&#xff0c;缺少ServicePack1. 解決辦法是&#xff0c;打開控制面板\系統和安全\Windows Update&#xff0c;下載和更新計算機安裝&#xff0c;然后卸載以前的python版…

在Java中衡量執行時間– Spring StopWatch示例

有兩種方法可以通過使用System.currentTimeinMillis&#xff08;&#xff09;或通過使用System.nanoTime&#xff08;&#xff09; 來測量Java中經過的執行時間 。 這兩個方法可用于測量 Java中兩個方法調用或事件之間的經過時間或執行時間 。 計算經過的時間是Java程序員要做的…

c語言getch在哪個頭文件,用getch()需要頭文件嗎?

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include #include "string.h"#includeusing namespace std;struct student{ int num;char name[10];char banji[10];float score[3];struct student *next;};struct student *creat(){struct student *head,*p…

My solution for Git Client Error: Permission denied (publickey)

在使用Git客戶端的過程中遇到的問題以及解決方案分享。 我之前已經安裝Git客戶端并且使用Git開發過公司項目&#xff0c;也已經正確生成PublicKey并且添加到SSH keys on github of my account&#xff0c;但是當我想從github上克隆另一個客戶端push的代碼的時候一直報錯&#x…

OutOfMemoryError:無法創建新的本機線程–問題神秘化

正如您從我以前的教程和案例研究中可能已經看到的那樣&#xff0c;要確定和解決Java Heap Space OutOfMemoryError問題可能很復雜。 我從Java EE生產系統中觀察到的常見問題之一是OutOfMemoryError&#xff1a;無法創建新的本機線程&#xff1b; HotSpot JVM無法進一步創建新的…

求10以內平均數的c語言,求助 給小學生出題,自己選加減乘除 做10題 10以內的數 然后統計分...

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include #include void Menu(void){printf("1,加法 2,減法 3,乘法 4,除法 5,退出\n");printf("請選擇題目類型:");}int Plus(void){int a, b;a rand() % 10 1;b rand() % 10 1;printf("%-2…

linux常用命令大全(轉)好東西要分享

1、ls命令 就是list的縮寫&#xff0c;通過ls 命令不僅可以查看linux文件夾包含的文件&#xff0c;而且可以查看文件權限(包括目錄、文件夾、文件權限)查看目錄信息等等 常用參數搭配&#xff1a; ls -a 列出目錄所有文件&#xff0c;包含以.開始的隱藏文件 ls -A 列出除.及.…

Cobertura和Maven:集成和單元測試的代碼覆蓋率

在姜黃項目中&#xff0c;我們每晚維護一個儀表板。 在儀表板上&#xff0c;我們收集有關項目的統計信息&#xff0c;包括代碼覆蓋率&#xff0c;findbugs分析和其他指標。 我們一直在使用Maven EMMA插件來提供代碼覆蓋&#xff0c;但是遇到了EMMA問題。 在對類進行檢測后&…