java程序中怎么保证多线程的运行安全_Java线程安全问答(草稿)
1.什么是線程安全?
如果一個類在多線程執行中,在不考慮運行環境的調度干預,也不需要調用代碼的協調同步,仍然保證正確地運行,那么這個類就是線程安全的
也就是說,多線程環境下,線程安全的類總是有正確的行為。但是這種類在實際情況中是很少的。
實際情況下的類一般分為5個類別(Java Concurrency in Practice》的作者Brian Goetz給出):
不可變的 這篇文章比較詳細的講述了不可變性。另外設計模式中,還有一個不變模式。
絕對安全/無條件的線程安全,通常來講這個類“怎么用怎么安全”,但我加了雙引號,其實還是要注意的
相對安全/有條件的,方法單個使用是沒問題的,但為了處理某些業務按照順序連續調用需要同步
線程兼容/非線程安全,需要外部同步保證
線程對立,沒法協調做到安全
這篇文章的最后給出了這5個級別的更多解釋。
2.為什么也好關注線程安全?
隨著軟硬件的發展,Java代碼運行在多處理器環境中。
2.1spring單例,tomcat線程池
spring容器中,類多是單例的。
而web服務器為了提高性能,都是用了線程池處理請求。
2.2提升效率,自己開啟新線程
為了提升效率,
應用中也會存在開啟多個線程分隔處理多個任務。
或者自己維護線程池處理異步任務的情況。
此時,多個線程的協調和交互都需要關注線程安全。
java中類中的屬性會同時有多個線程訪問。
3.為什么是類中的屬性?方法參數不需要關注線程安全嗎?
JVM內存結構圖
是屬性還是方法參數取決于在jaa運行時共享的資源
這篇文章講述了java運行時共享的那個資源。
這篇文章從java內存模型的角度分析java中屬性和方法參數在底層的實現。
4.怎么才能保證線程安全呢?
需要保證 原子性,可見性,有序性。
5.什么是原子性?為什么要考慮原子性?
一個線程可能對某個屬性有多個操作,比如i=i++。可以分解為2個動作
原子性就是這個操作在2步操作中是都必須要完成的,中間不能有其他線程的操作。對其他線程來說這個操作是排他的。
這個保證原子性的過程,需要鎖的參與。除了排他鎖,還有其他鎖。
這篇文章http://ifeve.com/java_lock_see/ 講的比較詳細,也比較有難度。實際上java已經提供了鎖的實現,直接使用即可。
加鎖同時保證了有序性和可見性。
7,什么是可見性?為什么要考慮可見性?
可見性是值一個線程的操作結果對其他線程可見。
為什么會有不可見的情況呢?這是由java的內存模型決定的,java的內存模型是一個抽象的概念,其具體組成是由cpu緩存,指令緩存等構成的。
為了不受其他因素影響,提升效率,java為每一個線程分配了內存空間叫“工作內存”,執行過程中,
每個線程會從“主內存”拷貝一份數據到工作內存。并在工作內存中計算完成之后將計算結果回寫到主內存。比如i++操作。
多個線程的工作內存是不可見的,只有在主內存的數據才可見。
java中的關鍵字volatile 抑制了一些線程運行上的優化,保證了可見性。比如對volatile變量的操作,任何線程的操作都不再拷貝數據到自己的工作內存,而是直接在主內存中操作。這樣保證了多個線程的操作都是可見的,同時也保證了部分的有序性,但是降低了效率。
JVM中每個線程會有自己的棧,而堆是存放各線程所用對象的地方。堆類似于JMM中的主內存,棧中的一部分類似工作內存。
8 .什么是有序性?為什么要考慮有序性?
java為了線程的高效并發執行,也是為了配合工作內存或者說緩存的有效利用,除了工作內存機制的優化之外,還有“指令重排序”。所以需要考慮有序性。
有序性在多線程環境中比較復雜,有序性是指某個操作(操作B)的結果可能需要前一個操作(操作A)的結果前提下完成。
正確的結果應該是操作A-->操作B.不應該出現這種情況操作B-->操作A.
本線程內觀察,線程內的所有操作有序,一個線程觀察另外一個則無序。
多線程環境中保證有序性,需要遵循happens-before原則,這個原則是重排序的一個默認保證(這個如果不保證,則代碼的執行結果不可預見,每次執行都可能不同,這是不可接受的):
Program order rule. 線程內的代碼能夠保證執行的先后順序
Monitor lock rule. 對于同一個鎖,一個解鎖操作一定要發生在時間上后發生的另一個鎖定操作之前
Volatile variable rule. 保證前一個對volatile的寫操作在后一個volatile的讀操作之前
Thread start rule. 一個線程內的任何操作必需在這個線程的start()調用之后
Thread termination rule. 一個線程的所有操作都會在線程終止之前
Interruption rule. 要保證interrupt()的調用在中斷檢查之前發生
Finalizer rule. 一個對象的終結操作的開始必需在這個對象構造完成之后
Transitivity. 可傳遞性 9,這8條原則怎么理解呢?
可以參考
http://blog.163.com/javaee_chen/blog/static/179195077201131382128499/
http://ifeve.com/easy-happens-before/
http://javatar.iteye.com/blog/144763
10,雙重檢查鎖定為什么會失效?
雙重檢查鎖定是:
失效的原因主要有:
1.指令重排序
2.內存的可見性
http://ifeve.com/doublecheckedlocking/
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的java程序中怎么保证多线程的运行安全_Java线程安全问答(草稿)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java重入锁_java并发编程:可重入
- 下一篇: Java接口四个类四则运算_用JAVA设