第1章 簡介
略,覺得沒有必要寫筆記,一堆介紹,沒有什么實際作用。
第2章 線程安全
2.1 什么是線程安全?
默認情況下,我們創建n個線程,線程的執行順序不是由我們程序員而決定的,而是由cpu的調度器決定,然后這並不是我們想要的效果,我們希望可以控制線程,操縱多線程,來幫助我們完成多個任務。
那什么是線程安全啊呢?
多線程在共同使用一個變量的時候,會出現爭奪變量的情況,最后的結果就是,計算完畢后,計算的結果是錯誤的,於是乎我們需要讓線程有序,不出現爭奪變量的情況,有序的手段就是對變量上鎖,這樣就可以保證線程是安全的。
2.2原子性
原子是不可分割的,我覺得在線程中談原子性,應該是多個線程訪問同一個變量的時候,在同一時刻,只能有一個線程去讀寫變量,只要這個線程沒有讀寫完畢,其他線程就無法去讀寫變量。
2.2.1竟態條件
Condition,線程競爭的條件,通過創建不同Condition,notFull、notNull之類的對象,來達到精確控制鎖的目的,一般和重入鎖結合使用。
2.3加鎖機制
2.3.1內置鎖
synchronized,修飾代碼塊,或者修飾方法體
2.3.2重入鎖
ReentrantLockclass X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
2.4用鎖來保護狀態
用鎖可以讓公共的變量處於獨占狀態,這樣就可以保證在多線程的環境中,每個線程不會獲取到錯誤的數據。
2.5活躍性與性能
不要對執行時間較長的計算,或者可能無法快速完成的操作加鎖。
盡量縮小synchronized的范圍,范圍比較大的話,作者說這屬於不良並發,不良並發就是為了安全,而放棄了大量的性能。
第3章 對象的共享
3.1 可見性
舉個例子,來說明可見性。
有線程1、2、3,有int n = 0;
在多線程的環境中,假設線程1爭取到了讀寫權,把n修改成了1,如果程序具有可見性,那么2、3是可以看到n的最新值,也就是1。
這就是變量的可見性,我覺得書中想表達的就是這個意思。
3.1.1 失效的數據
作者寫了一個demo,證明了在多線程的情況下,線程會讀取到錯誤的數據。
避免的方式就是使用同步機制。。。
3.1.2 非原子的64位操作
java內存模型中規定,變量的讀操作或者寫操作必須是原子操作,但是,對於非volatile的long和double變量,jvm中允許將64位的讀寫操作拆成2個32位的操作。所以在多線程的環節中執行上述操作,可能會隨機的獲取到2個32位操作中的某個,所以在多線程的環境中公共變量就用volatile來修飾,這樣就安全了。
3.1.3 加鎖與可見性
書中畫了一張圖,圖中有線程A和線程B,線程A先執行,B后執行,線程A對變量做的修改,線程B執行的時候是可以獲取到之前線程A修改的值,就是可見性。
3.1.4 volatile變量
論述了volatile只具有可見性,volatile是一種輕量級的加鎖機制,適用場景一般就是發布狀態。
volatile和synchronized的取舍,volatile能做到的,用synchronized也同樣可以做到,只是在一些少數情形下,使用volatile更優而已。
3.2發布與逸出
發布:把對象用public 和 static 修飾,就可以是發布了
逸出:簡而言之就是一些私有屬性,本來是封裝於Class中,是不應該發布的,但是由於一些其他原因變為共有狀態,不具有私有性。
書中介紹,防止逸出的辦法就是使用工廠方法,來創建對象。
3.3線程封閉