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