A. 怎麼理解Stringbuffer 是線程安全的 stringbuilder是線程不安全的
線程安全,主要是指多線程操作同一個數據時,防止臟數據的產生。主要的應用場景是應用緩存,緩存是整個系統公用的數據,在多線程系統中,線程的非同步訪問和修改會導致數據產生異常。
考慮一個場景,A和B兩個線程同時操作緩存中的一條數據,A線程對數據進行自加處理,B線程對數據進行校驗,如果校驗不過,就清除數據。
非線程安全的情況:當A獲取到這條數據,准備修改時,B線程進來了,校驗完數據,發現數據不正確,就把數據移除了,這時A線程仍舊認為當前持有的數據還是開始獲取的數據,這樣再做處理就會報空。
線程安全的情況:就是當一個線程需要對這個數據進行改寫時,會給這個數據上一個同步鎖,比如A線程拿到數據後,給數據加上同步鎖,這時候B線程進來了,但是這時候數據已經上鎖,B線程則需要等待A線程釋放鎖之後才能對數據進行操作,這樣就防止了臟數據的產生。
JavaAPI的Stringbuffer和HashTable是在較低版本的JDK中提供的。隨著軟體項目越來越負責,系統對於性能要求越來越高,然而線程的同步訪問對系統性能有很大的影響,所以才會有效率更高的StringBuilder和HashMap的產生。當然在使用這些非線程安全的集合時,線程安全問題就需要開發人員自己控制。
StringBuffer是可變類,和線程安全的字元串操作類,任何對它指向的字元串的操作都不會產生新的對象。 每個StringBuffer對象都有一定的緩沖區容量,當字元串大小沒有超過容量時,不會分配新的容量,當字元串大小超過容量時,會自動增加容量。
StringBuffer buf=new StringBuffer(); //分配長16位元組的字元緩沖區
StringBuffer buf=new StringBuffer(512); //分配長512位元組的字元緩沖區
StringBuffer buf=new StringBuffer("this is a test")//在緩沖區中存放了字元串,並在後面預留了16位元組的空緩沖區。StringBuffer
StringBuffer和StringBuilder類功能基本相似,主要區別在於StringBuffer類的方法是多線程、安全的,而StringBuilder不是線程安全的,相比而言,StringBuilder類會略微快一點。對於經常要改變值的字元串應該使用StringBuffer和StringBuilder類。線程安全
StringBuffer 線程安全
StringBuilder 線程不安全速度
一般情況下,速度從快到慢:StringBuilder>StringBuffer>String,這種比較是相對的,不是絕對的。總結
(1).如果要操作少量的數據用 = String
(2).單線程操作字元串緩沖區 下操作大量數據 = StringBuilder
(3).多線程操作字元串緩沖區 下操作大量數據 = StringBuffer
B. string和stringbuffer和stringbuilder的區別
string和stringbuffer和stringbuilder的區別:
StringBuffer線程安全,StringBuilder線程不安全。緩沖區:StringBuffer直接使用toStringCache構造字元串。StringBuilder復制字元數組再構造。
性能:StringBuilder的性能要遠大於StringBuffer。
線程安全:StringBuffer:線程安全,StringBuilder:線程不安全。
因為StringBuffer的所有公開方法都是synchronized修飾的,StringBuilder並沒有StringBuilder修飾。
緩沖區:StringBuffer每次獲取toString都會直接使用緩存區的toStringCache值來構造一個字元串。而StringBuilder則每次都需要復制一次字元數組,再構造一個字元串。
所以,緩存沖這也是對 StringBuffer 的一個優化吧,不過 StringBuffer 的這個toString 方法仍然是同步的。
性能:StringBuffer是線程安全的,它所有公開方法都是同步的,StringBuilder是沒有對方法加鎖同步的,所以毫無疑問,StringBuilder的性能要遠大於 StringBuffer。
C. java的線程安全跟非安全到底是什麼意思
比如某個變數
int a=0;
2個線程同時分別對其加5,000,000次。結果如果能保證得到總共的a:=10,000,000,這時就說是線程安全thread-safe的。
事實上同時加的話,由於變數在內存中有緩存,非常容易漏加。導致計算嚴重不準確。
比如在多線程動畫的坐標計算上,同步不當會導致畫亂。這時候就說這個變數a是線程不安全non-thread-safe。
需要用java synchronize同步關鍵字確保同一時間只有一個線程在寫該變數。
D. 怎麼理解Stringbuffer 是線程安全的 stringbuilder是線程不安全的
1.多個線程操作同一個StringBuffer對象會順序進行(內部很多方法是同步方法)
2.多個線程操作同一個StringBuilder是同時的,這時候可能出現與預期不符合的結果
3.StringBuilder由於是線程不安全的,所以性能更好。大部分情況下都是單線程操作字元串,這時候選擇StringBuilder。
E. 如何創建線程如何保證線程安全
線程安全等級
之前的博客中已有所提及「線程安全」問題,一般我們常說某某類是線程安全的,某某是非線程安全的。其實線程安全並不是一個「非黑即白」單項選擇題。按照「線程安全」的安全程度由強到弱來排序,我們可以將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伺服器應用都可以使用線程本地存儲來解決線程安全問題。
F. java如何實現線程安全的緩存
簡單來說就是多線程的時候,多線程同時修改同一個類的時候,由於訪問順序隨機導致類功能出錯,至於線程安全類設計方法很多的,Java可以用synchronize標識類,只允許一個線程在同一時間訪問它,選擇線程安全的數據類型例如ArrayList,數組是不安全的,你可以多去網路查!
G. 網頁緩存的生命周期是多少
有很多理由去解釋理解ASP.NET頁面生命周期是非常重要的,主要是要去理解什麼地方放置什麼特定的方法,什麼時候我們應該設置什麼相關的屬性。如果去開發自定義的伺服器控制項,理解生命周期對糾正控制項初始化時候的錯誤,以及使用view-state和後台代碼設置屬性是非常有用的。(控制項事件只與ASP.NET頁面相關)
頁面生命周期要看它是否是第一次請求,還是回發(本身頁面請求),最後決定是否到Web伺服器。當一個網頁被Web伺服器請求時,在回發到web瀏覽器之前,會經過一系列步驟/事件(如初始化,控制項實例化,state的恢復和保存,執行事件處理代碼,渲染)。
如果我們正確地使用和操作頁面生命周期事件,它對web應用程序開發會是一個非常方便和強大的工具。