導航:首頁 > 編程語言 > java線程安全問題

java線程安全問題

發布時間:2022-09-04 04:45:55

java中的線程安全是什麼什麼叫線程安全什麼叫不安全

java中的線程安全是什麼:
就是線程同步的意思,就是當一個程序對一個線程安全的方法或者語句進行訪問的時候,其他的不能再對他進行操作了,必須等到這次訪問結束以後才能對這個線程安全的方法進行訪問

什麼叫線程安全:
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程序所提供的介面對於線程來說是原子操作或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。
線程安全問題都是由全局變數及靜態變數引起的。
若每個線程中對全局變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全局變數是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。

② Java的List如何實現線程安全

解決這個問題通常有兩種方法(個人認為)
一:使用synchronized關鍵字,這個大家應該都很熟悉了,不解釋了;
二:使用Collections.synchronizedList();使用方法如下:
假如你創建的代碼如下:List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();
那麼為了解決這個線程安全問題你可以這么使用Collections.synchronizedList(),如:
List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>());
其他的都沒變,使用的方法也幾乎與ArrayList一樣,大家可以參考下api文檔;
額外說下 ArrayList與LinkedList;這兩個都是介面List下的一個實現,用法都一樣,但用的場所的有點不同,ArrayList適合於進行大量的隨機訪問的情況下使用,LinkedList適合在表中進行插入、刪除時使用,二者都是非線程安全,解決方法同上(為了避免線程安全,以上採取的方法,特別是第二種,其實是非常損耗性能的)。

③ java是線程安全的嗎

線程安全就是多線程訪問時,採用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。不會出現數據不一致或者數據污染。(Vector,HashTab;le)
線程不安全就是不提供數據訪問保護,有可能出現多個線程先後更改數據造成所得到的數據是臟數據。(ArrayList,LinkedList,HashMap等)
概念:
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是線程安全的。或者說:一個類或者程序所提供的介面對於線程來說是原子操作或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。線程安全問題都是由全局變數及靜態變數引起的。
若每個線程中對全局變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全局變數是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
例子:
比如一個 ArrayList 類,在添加一個元素的時候,它可能會有兩步來完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。
在單線程運行的情況下,如果 Size = 0,添加一個元素後,此元素在位置 0,而且 Size=1;
而如果是在多線程情況下,比如有兩個線程,線程 A 先將元素存放在位置 0。但是此時 CPU 調度線程A暫停,線程 B
得到運行的機會。線程B也向此 ArrayList 添加元素,因為此時 Size 仍然等於 0
(注意哦,我們假設的是添加一個元素是要兩個步驟哦,而線程A僅僅完成了步驟1),所以線程B也將元素存放在位置0。然後線程A和線程B都繼續運行,都增加
Size 的值。
那好,我們來看看 ArrayList 的情況,元素實際上只有一個,存放在位置 0,而 Size 卻等於 2。這就是「線程不安全」了。
安全性:
線程安全性不是一個非真即假的命題。 Vector 的方法都是同步的,因為java會有相應的機制是同一時刻只有一個線程對這個變數操作。並且
Vector 明確地設計為在多線程環境中工作。但是它的線程安全性是有限制的,即在某些方法之間有狀態依賴(類似地,如果在迭代過程中 Vector
被其他線程修改,那麼由 Vector.iterator() 返回的
iterator會拋出)。
對於 Java 類中常見的線程安全性級別,沒有一種分類系統可被廣泛接受,不過重要的是在編寫類時盡量記錄下它們的線程安全行為。
Bloch 給出了描述五類線程安全性的分類方法:不可變、線程安全、有條件線程安全、線程兼容和線程對立。只要明確地記錄下線程安全特性,那麼您是否使用這種系統都沒關系。這種系統有其局限性
– 各類之間的界線不是百分之百地明確,而且有些情況它沒照顧到 –
但是這套系統是一個很好的起點。這種分類系統的核心是調用者是否可以或者必須用外部同步包圍操作(或者一系列操作)。下面幾節分別描述了線程安全性的這五種類別。
不可變
不可變的對象一定是線程安全的,並且永遠也不需要額外的同步。因為一個不可變的對象只要構建正確,其外部可見狀態永遠也不會改變,永遠也不會看到它處於不一致的狀態。Java
類庫中大多數基本數值類如 Integer 、 String 和 BigInteger 都是不可變的。
需要注意的是,對於Integer,該類不提供add方法,加法是使用+來直接操作。而+操作是不具線程安全的。這是提供原子操作類AtomicInteger的原。
線程安全
線程安全的對象具有在上面「線程安全」一節中描述的屬性 –
由類的規格說明所規定的約束在對象被多個線程訪問時仍然有效,不管運行時環境如何排線程都不需要任何額外的同步。這種線程安全性保證是很嚴格的 –
許多類,如 Hashtable 或者 Vector 都不能滿足這種嚴格的定義。
有條件的線程安全
有條件的線程安全類對於單獨的操作可以是線程安全的,但是某些操作序列可能需要外部同步。條件線程安全的最常見的例子是遍歷由 Hashtable
或者 Vector 或者返回的迭代器 – 由這些類返回的 fail-fast
迭代器假定在迭代器進行遍歷的時候底層集合不會有變化。為了保證其他線程不會在遍歷的時候改變集合,進行迭代的線程應該確保它是獨占性地訪問集合以實現遍歷的完整性。通常,獨占性的訪問是由對鎖的同步保證的
– 並且類的文檔應該說明是哪個鎖(通常是對象的內部監視器(intrinsic monitor))。
如果對一個有條件線程安全類進行記錄,那麼您應該不僅要記錄它是有條件線程安全的,而且還要記錄必須防止哪些操作序列的並發訪問。用戶可以合理地假設其他操作序列不需要任何額外的同步。
線程兼容
線程兼容類不是線程安全的,但是可以通過正確使用同步而在並發環境中安全地使用。這可能意味著用一個 synchronized
塊包圍每一個方法調用,或者創建一個包裝器對象,其中每一個方法都是同步的(就像 Collections.synchronizedList()
一樣)。也可能意味著用 synchronized
塊包圍某些操作序列。為了最大程度地利用線程兼容類,如果所有調用都使用同一個塊,那麼就不應該要求調用者對該塊同步。這樣做會使線程兼容的對象作為變數實例包含在其他線程安全的對象中,從而可以利用其所有者對象的同步。
許多常見的類是線程兼容的,如集合類 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 類 Connection 和 ResultSet 。
線程對立
線程對立類是那些不管是否調用了外部同步都不能在並發使用時安全地呈現的類。線程對立很少見,當類修改靜態數據,而靜態數據會影響在其他線程中執行的其他類的行為,這時通常會出現線程對立。線程對立類的一個例子是調用 System.setOut() 的類。

④ 如何創建線程如何保證線程安全

線程安全等級

之前的博客中已有所提及「線程安全」問題,一般我們常說某某類是線程安全的,某某是非線程安全的。其實線程安全並不是一個「非黑即白」單項選擇題。按照「線程安全」的安全程度由強到弱來排序,我們可以將java語言中各種操作共享的數據分為以下5類:不可變、絕對線程安全、相對線程安全、線程兼容和線程對立。

1、不可變

在java語言中,不可變的對象一定是線程安全的,無論是對象的方法實現還是方法的調用者,都不需要再採取任何的線程安全保障措施。如final關鍵字修飾的數據不可修改,可靠性最高。

2、絕對線程安全

絕對的線程安全完全滿足Brian GoetZ給出的線程安全的定義,這個定義其實是很嚴格的,一個類要達到「不管運行時環境如何,調用者都不需要任何額外的同步措施」通常需要付出很大的代價。

3、相對線程安全

相對線程安全就是我們通常意義上所講的一個類是「線程安全」的。

它需要保證對這個對象單獨的操作是線程安全的,我們在調用的時候不需要做額外的保障措施,但是對於一些特定順序的連續調用,就可能需要在調用端使用額外的同步手段來保證調用的正確性。

在java語言中,大部分的線程安全類都屬於相對線程安全的,例如Vector、HashTable、Collections的synchronizedCollection()方法保證的集合。

4、線程兼容

線程兼容就是我們通常意義上所講的一個類不是線程安全的。

線程兼容是指對象本身並不是線程安全的,但是可以通過在調用端正確地使用同步手段來保證對象在並發環境下可以安全地使用。Java API中大部分的類都是屬於線程兼容的。如與前面的Vector和HashTable相對應的集合類ArrayList和HashMap等。

5、線程對立

線程對立是指無論調用端是否採取了同步錯誤,都無法在多線程環境中並發使用的代碼。由於java語言天生就具有多線程特性,線程對立這種排斥多線程的代碼是很少出現的。

一個線程對立的例子是Thread類的supend()和resume()方法。如果有兩個線程同時持有一個線程對象,一個嘗試去中斷線程,另一個嘗試去恢復線程,如果並發進行的話,無論調用時是否進行了同步,目標線程都有死鎖風險。正因此如此,這兩個方法已經被廢棄啦。

二、線程安全的實現方法

保證線程安全以是否需要同步手段分類,分為同步方案和無需同步方案。

1、互斥同步

互斥同步是最常見的一種並發正確性保障手段。同步是指在多線程並發訪問共享數據時,保證共享數據在同一時刻只被一個線程使用(同一時刻,只有一個線程在操作共享數據)。而互斥是實現同步的一種手段,臨界區、互斥量和信號量都是主要的互斥實現方式。因此,在這4個字裡面,互斥是因,同步是果;互斥是方法,同步是目的。

在java中,最基本的互斥同步手段就是synchronized關鍵字,synchronized關鍵字編譯之後,會在同步塊的前後分別形成monitorenter和monitorexit這兩個位元組碼質量,這兩個位元組碼指令都需要一個reference類型的參數來指明要鎖定和解鎖的對象。

此外,ReentrantLock也是通過互斥來實現同步。在基本用法上,ReentrantLock與synchronized很相似,他們都具備一樣的線程重入特性。

互斥同步最主要的問題就是進行線程阻塞和喚醒所帶來的性能問題,因此這種同步也成為阻塞同步。從處理問題的方式上說,互斥同步屬於一種悲觀的並發策略,總是認為只要不去做正確地同步措施(例如加鎖),那就肯定會出現問題,無論共享數據是否真的會出現競爭,它都要進行加鎖。

2、非阻塞同步

隨著硬體指令集的發展,出現了基於沖突檢測的樂觀並發策略,通俗地說,就是先進行操作,如果沒有其他線程爭用共享數據,那操作就成功了;如果共享數據有爭用,產生了沖突,那就再採用其他的補償措施。(最常見的補償錯誤就是不斷地重試,直到成功為止),這種樂觀的並發策略的許多實現都不需要把線程掛起,因此這種同步操作稱為非阻塞同步。

非阻塞的實現CAS(compareandswap):CAS指令需要有3個操作數,分別是內存地址(在java中理解為變數的內存地址,用V表示)、舊的預期值(用A表示)和新值(用B表示)。CAS指令執行時,CAS指令指令時,當且僅當V處的值符合舊預期值A時,處理器用B更新V處的值,否則它就不執行更新,但是無論是否更新了V處的值,都會返回V的舊值,上述的處理過程是一個原子操作。

CAS缺點:

ABA問題:因為CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。

ABA問題的解決思路就是使用版本號。在變數前面追加版本號,每次變數更新的時候把版本號加一,那麼A-B-A就變成了1A-2B-3C。JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等於預期引用,並且當前標志是否等於預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。

3、無需同步方案

要保證線程安全,並不是一定就要進行同步,兩者沒有因果關系。同步只是保證共享數據爭用時的正確性的手段,如果一個方法本來就不涉及共享數據,那它自然就無需任何同步操作去保證正確性,因此會有一些代碼天生就是線程安全的。

1)可重入代碼

可重入代碼(ReentrantCode)也稱為純代碼(Pure Code),可以在代碼執行的任何時刻中斷它,轉而去執行另外一段代碼,而在控制權返回後,原來的程序不會出現任何錯誤。所有的可重入代碼都是線程安全的,但是並非所有的線程安全的代碼都是可重入的。

可重入代碼的特點是不依賴存儲在堆上的數據和公用的系統資源、用到的狀態量都是由參數中傳入、不調用 非可重入的方法等。

(類比:synchronized擁有鎖重入的功能,也就是在使用synchronized時,當一個線程得到一個對象鎖後,再次請求此對象鎖時時可以再次得到該對象的鎖)

2)線程本地存儲

如果一段代碼中所需的數據必須與其他代碼共享,那就看看這些共享數據的代碼是否能保證在同一個線程中執行?如果能保證,我們就可以把共享數據的可見范圍限制在同一個線程之內。這樣無需同步也能保證線程之間不出現數據的爭用問題。

符合這種特點的應用並不少見,大部分使用消費隊列的架構模式(如「生產者-消費者」模式)都會將產品的消費過程盡量在一個線程中消費完。其中最重要的一個應用實例就是經典的Web交互模型中的「一個請求對應一個伺服器線程(Thread-per-Request)」的處理方式,這種處理方式的廣泛應用使得很多Web伺服器應用都可以使用線程本地存儲來解決線程安全問題。

⑤ java中的線程安全問題

其實就一句話:只要是有多個線程訪問並修改某個變數或是區域的話,一定要加上同步設置(比如同步控制語句,互斥鎖,信號量,原子操作等等)。
b/s結構中,如果你不編寫類似apache等的http
server,那麼你不用考慮線程安全這個問題。
如果有多個用戶訪問資料庫的情況出現:
1.若資料庫中間件封裝了同步功能,則不需要考慮線程安全;
2.若資料庫本身支持並發操作,則不需要考慮線程安全;
3.否則則需要考慮線程安全的問題。

⑥ 如何確保Java線程安全

在Java中可以有很多方法來保證線程安全——同步,使用原子類(atomicconcurrentclasses),實現並發鎖,使用volatile關鍵字,使用不變類和線程安全類。

⑦ Java中所說的線程安全是指什麼

關於線程安全,是指當多個線程訪問同一個變數時,該變數不會因為多線程訪問產生意想不到的問題,為了避免多線程訪問的不可預知的問題,對於程序中多線程能訪問到的變數要加鎖,即加synchronized,放在同步塊中,或者對改變該變數值的方法加synchronized限制。當然jdk中自帶的一些類本身就實現了該機制,本身就是線程安全的,比如StringBuffer,Vector等。

⑧ Java開發中線程的安全問題以及產生的原因

Java如何保證原子性常用的保證Java操作原子性的工具是鎖和同步方法(或者同步代碼塊)。使用鎖,可以保證同一時間只有一個線程能拿到鎖,也就保證了同一時間只有一個線程能執行申請鎖和釋放鎖之間的代碼。
與鎖類似的是同步方法或者同步代碼塊。使用非靜態同步方法時,鎖住的是當前實例;使用靜態同步方法時,鎖住的是該類的Class對象;使用靜態代碼塊時,鎖住的是synchronized關鍵字後面括弧內的對象。

⑨ 幾個關於java線程安全的老問題。

1.錯,只有當多個線程訪問並修改同一個帶屬性的對象時才產生線程安全問題
2.在多線程共享的情況下成立
3.仍然會有線程安全問題,除非不使用任何共享屬性
4.沒看出問題

5.對的

⑩ Java中如何使方法線程安全

線程不安全的場合很多,比如像操作系統中的用戶界面、列印機等外設、控制台輸出,都不允許並發(設想兩個程序同時要輸出文字到同一個屏幕,那還不亂套了)
在代碼中,每個線程有自己的堆棧但是共享整個堆,所以訪問那些全局的變數,也必須同步,否則會出現臟讀數據。
同步也不是萬能的良葯。不當的鎖定會導致程序死鎖,而且多線程本身就是為了提高性能,但是同步使用多了,程序又實質上退化成了單線程程序,用多線程的意義也就沒了。

閱讀全文

與java線程安全問題相關的資料

熱點內容
hexophp 瀏覽:271
用什麼app買東西半價 瀏覽:62
蘋果下載的pdf文件怎麼打開 瀏覽:211
如何在伺服器上隱藏源站地址 瀏覽:645
單片機進制字母對應表 瀏覽:528
向某人下命令 瀏覽:627
編程中刪除數組中的數 瀏覽:86
aes對稱加密反編譯 瀏覽:550
java編譯成exe 瀏覽:190
gps處理演算法 瀏覽:596
什麼app可以和對象存錢 瀏覽:146
java字元串表達式計算 瀏覽:330
javacmd環境變數 瀏覽:51
電視上面找不到全民歌app怎麼辦 瀏覽:156
單片機中psw0 瀏覽:994
優酷視頻加密么 瀏覽:763
本地連接dos命令 瀏覽:206
雲伺服器怎麼上傳金幣房卡游戲 瀏覽:71
Python快遞管理可視化 瀏覽:419
java正則驗證數字 瀏覽:830