java并发编程实战学习笔记之基础知识与对象的共享
第二章:線程安全性
2.1 什么是線程安全性
可以被多個線程調用,并且在線程之間不會出現錯誤的交互
方法內的局部變量不需要保護,因為它存儲在棧中,是每個線程獨有的
2.2 原子性
一個共享變量可以定義為原子變量:atomic
多個共享變量時,之間可能存在某種依賴關系,分別定義為原子變量會由于競態條件,出現錯誤,比如先檢查后執行。
競態條件:某個計算的正確性取決于多個線程的交替執行時序時
這就需要復合操作,將多個變量的讀寫操作作為一個程序塊,接下來采用
2.3 加鎖機制
將一個復合程序塊采用內置鎖加鎖。synchronized,把方法調用所在的對象作為一個鎖,相當于一個互斥體,程序塊只能被該對象進入,但是由于內置鎖是可重入的,也就是程序塊可以被該對象多次進入,常用于子類復寫基類的synchronized方法時。
2.4 用鎖來保護狀態
不止可用內置鎖,還可以用顯示的鎖來執行同步,且多個synchronized方法有相互依賴關系時,還需要其他的鎖機制
2.5 活躍性與性能
由于上述方法會造成性能非常低,如果一個程序塊用時較長,則后續線程會長時間等待,應該講鎖的粒度降低,但是在性能與程序簡單性方面要取得平衡
第三章 對象的共享
3.1 可見性
線程A修改變量i,線程B是否可立即看到?
synchronized不僅可以用來加鎖,還可以用來同步
非原子的64位操作:會被分解為兩個32位操作,因此必須在多線程環境下申明共享且可變的long或者double類型的數據時,用volatile修飾,或者加鎖保護。volatile用來將變量的更新同步到其他線程,只能用于可見性,不能用于原子性。在訪問volatile變量時不會執行加鎖操作,因此volatile是一種比synchronized更輕量級的同步機制。
volatile與加鎖的選擇:
volatile常用于簡單的狀態標志,但不保證遞增的原子性,在1、對變量的寫入不依賴當前值2、該變量不會與其他變量一起納入不可變條件中3、在訪問變量時不需要加鎖的情況下,才使用。
加鎖即可保證原子性,又可保證可見性。
3.2 對象的發布與逸出
當一個對象發布時,在該對象內引用的非私有對象一同被發布。
構造函數里的this指針很容易被逸出,可以用私有構造函數+實例工廠來避免
3.3 線程封閉
僅在單線程內訪問數據,叫做線程封閉。比如JDBC的connection對象。從連接池獲取一個connection對象,直到用完后返回,連接池不會將該對象分配給其他線程使用。
棧封閉:申明為一個方法中的局部變量
ThreadLocal類:用于防止對可變的單實例變量或全局變量進行共享。比如在一個進程中使用的一個connection對象,在其內部所有的方法都可使用,但不可被其他進程訪問。
3.4 不變性
不可變變量:final
3.5 安全發布
多個線程間共享對象,必須確保安全的共享
可變對象必須通過安全的方式來發布,也就是必須使用同步。一個正確構造的對象可通過以下方式來發布:1、在靜態初始化函數中初始化一個對象引用2、將對象的引用保存到volatile類型的域或者atomicReferance類型的對象中3、將對象的引用保存到某個正確構造對象的final域中4、將對象的引用保存到由一個鎖保護的域中
轉載于:https://blog.51cto.com/muyunzhe/1719927
總結
以上是生活随笔為你收集整理的java并发编程实战学习笔记之基础知识与对象的共享的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Orchard中如何配置远端发布
- 下一篇: 使用VMDepot镜像快速部署CKAN开