線程的安全的定義是複雜的,安全性中最核心的概念就是數據的正確性。
正確性
當多個線程訪問某個類時,這個類始終能表現出正確的行爲,那麼就稱這個類是安全的。
如果我們還是不懂這個正確性的定義,就舉一個反例來理解它。
public class ThreadSecStudy {
static int count = 0;
public static void main(String[] args) {
// 正確性反例
Thread add = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 50000; i++) {
count++;
System.out.println(count);
}
}
});
Thread cut = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 50000; i++) {
count--;
System.out.println(count);
}
}
});
// 加法
add.start();
// 減法
cut.start();
}
}
一定會有人覺得這段代碼從邏輯上是沒有任何問題的,一加一減並且相同的次數,那麼結果一定等於0,這是我們心中的認爲的正確的行爲,但是實際上呢,最後輸出的並不是0。
-70
-69
-68
-67
而且每次的輸出都是不相同的,其中循環的次數越多偏差越大,與我們的正確性的概念是完全相反的,也就是說這個類是不安全的。
三個體現
- 原子性:提供互斥訪問,同一時刻只能有一個線程對數據進行操作(Atomic、CAS算法、synchronized、Lock)
- 可見性:一個主內存的線程如果進行了修改,可以及時被其他線程觀察到(synchronized、volatile)
- 有序性:如果兩個線程不能從 happens-before原則 觀察出來,那麼就不能觀察他們的有序性,虛擬機可以隨意的對他們進行重排序,導致其觀察觀察結果雜亂無序(happens-before原則)
我們就按照這幾個體現,來改造之前存在的不安全的類。
詳細介紹參考以下文章!
- 線程安全性-原子性
- 線程安全性-可見性
- 線程安全性-有序性
文章中出現的任何錯誤歡迎指正,共同進步!
最後做個小小廣告,有對WEB開發和網絡安全感興趣的,可以加羣一起學習和交流!
QQ:425343603