在單執行緒下,我們經常使用count++將count的值自增1,也不會發生什麼錯誤,但是在多執行緒下,可能使用count++結果可能就往往出乎我們的意料了.
我們以count++,一直從1加到5為例
public
class
threadcount
extends
thread
@override
public
void
run()}
public
static
void
main
(string[
] args)
}
執行結果(多次執行結果不一致,但最終結果都是每個執行緒的count值變為5):
記憶體模型:
方式一:
我們建立了3個執行緒,每個執行緒都有各自的count變數,自己減少自己的count變數的值.這樣的情況就是變數不共享,並不存在多個執行緒訪問同乙個例項變數的情況.
public
class
threadcount1
extends
thread
public
static
void
main
(string[
] args)
}
執行結果(多次執行結果不一致,count值可能為5可能不為5):
記憶體模型:
方式二:
我們還是新建了5個執行緒,但是他們是共享主記憶體中的count變數.我們改變共享變數中的值分為3步:
①.從主記憶體中取出
從執行結果就可以看出,執行緒b和a同時對count進行了處理,產生了執行緒安全的問題,使的最終結果變為了4.
注意:雖然system.out.println()
是同步的,但是count++操作確實在進入println()之前發生的
public
void
println
(string x)
}
①使用synchronized
進行同步,既能保證一致性又能保證原子性
@override
public
synchronized
void
run(
)
②…其它鎖,reentrantlock
等
執行結果(每次執行結果相同,count變為5):
方式三:使用鎖進行同步,使的同一時間只有乙個執行緒能夠進行訪問.(原理以後細講)
private
volatile integer count =
0;
執行結果(每次執行結果不同,count的值不一定為5)
可見性:即對於乙個volatile的讀總能看到(任意執行緒)對這個volatile變數最後的寫入.(原理:記憶體遮蔽)
原子性:對任意單個volatile變數的讀/寫具有原子性,但類似於volatile++這種復合操作不具有原子性
count++並不是乙個原子操作,它分為3步:
?①.從記憶體中取出原有的count值
?②.進行i++的操作
?③.把count++後的值賦給count並寫入到主記憶體
private
static atomicinteger count =
newatomicinteger(0
);@override
public
void
run(
)
執行結果(每次執行結果不相同,count變為5):
方式四:使用atomicinteger
類並呼叫incrementandget
進行count++的操作.(原理:cas)
因為我對juc下的一些類不太了解,以後深入理解了在來繼續寫
談一下稀疏陣列
對於乙個初窺資料結構的人來說,稀疏陣列確實可以很好的幫助你鍛鍊思維。但自從第三次科技革命後,人們都一直在做著用空間去換取時間的損事,而以時間換空間的稀疏陣列,倒也跟北大考古專業有些心心相惜。當乙個陣列中大部分元素為0,或者為同乙個值時,可以使用稀疏陣列來儲存該陣列 小規模陣列便是稀疏陣列 像在編寫的...
簡談一下時間輪(Time Wheel)
如果乙個程式設計師不知道 time wheel,那麼那個程式設計師一定不是個合格的程式設計師。timer對於作業系統還是乙個虛擬機器語言或大型中介軟體都起著重要的作用,同時timer演算法的選擇也直接影響著效能。time wheel翻譯為時間輪,是用於實現定時器timer的經典演算法,演算法細節就不...
從頭到尾談一下HTTPS
你能談一下https嗎?一種比http安全的協議。如果面試這樣說的話那差不多就gg了,其實https要展開回答的話內容還挺豐富的。本篇文章詳細介紹了https是什麼 為什麼安全以及實現安全的方法,一起來學習吧。本文略長,請保持耐心。https是以安全為目標的http通道,簡單講是http的安全版。之...