線程安全
為什么有線程安全問題姑丑?
當多個線程同時共享让网,同一個全局變量或靜態(tài)變量呀忧,做寫的操作時,可能會發(fā)生數(shù)據(jù)沖突問題溃睹,也就是線程安全問題而账。但是做讀操作是不會發(fā)生數(shù)據(jù)沖突問題。
線程安全解決辦法:
問:如何解決多線程之間線程安全問題?
答:使用多線程之間同步synchronized或使用鎖(lock)因篇。
synchronized:效率很低
同步代碼塊:
什么是同步代碼塊泞辐?答:就是將可能會發(fā)生線程安全問題的代碼笔横,給包括起來。synchronized(同一個數(shù)據(jù)){
?可能會發(fā)生線程沖突問題的代碼
}
就是同步代碼塊?
synchronized(對象)//這個對象可以為任意對象?{
?????需要被同步的代碼?
}?
對象如同鎖咐吼,持有鎖的線程可以在同步中執(zhí)行?沒持有鎖的線程即使獲取CPU的執(zhí)行權吹缔,也進不去?
同步的前提:?
1,必須要有兩個或者兩個以上的線程?
2锯茄,必須是多個線程使用同一個鎖?必須保證同步中只能有一個線程在運行? ?
好處:解決了多線程的安全問題?
弊端:多個線程需要判斷鎖厢塘,較為消耗資源、搶鎖的資源肌幽。
同步函數(shù):
什么是同步函數(shù)晚碾?? ??
答:在方法上修飾synchronized 稱為同步函數(shù)
同步函數(shù)使用this鎖。一個線程用同步函數(shù)喂急,另一個用同步代碼塊格嘁,線程不同步。
靜態(tài)同步函數(shù)不用this鎖廊移,
問:為什么使用線程同步或使用鎖能解決線程安全問題呢糕簿?
答:將可能會發(fā)生數(shù)據(jù)沖突問題(線程不安全問題),只能讓當前一個線程進行執(zhí)行画机。代碼執(zhí)行完成后釋放鎖泞歉,讓后才能讓其他線程進行執(zhí)行芋簿。這樣的話就可以解決線程不安全問題嫌变。
問:什么是多線程之間同步俩滥?
答:當多個線程共享同一個資源,不會受到其他線程的干擾。
線程死鎖
死鎖主要是同步代碼塊或同步函數(shù)中嵌套同步引起的荚醒。
線程安全的三大特性
原子性芋类、可見性、有序性界阁。
簡單的說原子性就是多線程操作中要保障數(shù)據(jù)一致性侯繁,可見性就是多個線程訪問同一個變量時,某個線程對該變量的操作時泡躯,能夠讓其他線程可見(線程通信)贮竟,有序性就是多線程運行中對代碼的重排序不能影響代碼的邏輯。
以下詳細參考:
什么是原子性
即一個操作或者多個操作 要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷较剃,要么就都不執(zhí)行咕别。
一個很經典的例子就是銀行賬戶轉賬問題:比如從賬戶A向賬戶B轉1000元,那么必然包括2個操作:從賬戶A減去1000元写穴,往賬戶B加上1000元惰拱。這2個操作必須要具備原子性才能保證不出現(xiàn)一些意外的問題。
我們操作數(shù)據(jù)也是如此啊送,比如i = i+1偿短;其中就包括欣孤,讀取i的值,計算i昔逗,寫入i降传。這行代碼在Java中是不具備原子性的,則多線程運行肯定會出問題勾怒,所以也需要我們使用同步和lock這些東西來確保這個特性了搬瑰。
原子性其實就是保證數(shù)據(jù)一致、線程安全一部分控硼,
什么是可見性
當多個線程訪問同一個變量時,一個線程修改了這個變量的值艾少,其他線程能夠立即看得到修改的值卡乾。
若兩個線程在不同的cpu,那么線程1改變了i的值還沒刷新到主存缚够,線程2又使用了i幔妨,那么這個i值肯定還是之前的,線程1對變量的修改線程沒看到這就是可見性問題谍椅。
什么是有序性
程序執(zhí)行的順序按照代碼的先后順序執(zhí)行误堡。
一般來說處理器為了提高程序運行效率,可能會對輸入代碼進行優(yōu)化雏吭,它不保證程序中各個語句的執(zhí)行先后順序同代碼中的順序一致锁施,但是它會保證程序最終執(zhí)行結果和代碼順序執(zhí)行的結果是一致的。如下:
inta = 10;??? //語句1
intr = 2;??? //語句2
a =a + 3;? ??//語句3
r =a*a;???? //語句4
則因為重排序杖们,他還可能執(zhí)行順序為 2-1-3-4悉抵,1-3-2-4
但絕不可能 2-1-4-3,因為這打破了依賴關系摘完。顯然重排序對單線程運行是不會有任何問題姥饰,而多線程就不一定了,所以我們在多線程編程時就得考慮這個問題了孝治。