1.Synchronized
Synchronized關鍵字保證了數據讀寫一致和可見性等問題,但是他是一種阻塞的線程控制方法,在關鍵字使用期間,所有其他線程不能使用此變量。(同步機制採用了“以時間換空間”的方式)
修飾一個類
class ClassName {
public void method() {
synchronized(ClassName.class) {
// todo
}
}
}
修飾一個方法
public synchronized void method()
{
// todo
}
修飾一個代碼塊
public void method()
{
synchronized(this){
......
}
}
修飾一個靜態的方法
public synchronized static void method() {
// todo
}
2.volatile
volatile如何實現可見性?
volatile變量每次被線程訪問時,都強迫線程從主內存中重讀該變量的最新值,而當該變量發生修改變化時,也會強迫線程將最新的值刷新回主內存中。這樣一來,不同的線程都能及時的看到該變量的最新值。
但是volatile不能保證變量更改的原子性:
比 如number++,這個操作實際上是三個操作的集合(讀取number,number加1,將新的值寫回number),volatile只能保證每一 步的操作對所有線程是可見的,但是假如兩個線程都需要執行number++,那麼這一共6個操作集合,之間是可能會交叉執行的,那麼最後導致number 的結果可能會不是所期望的。
所以對於number++這種非原子性操作,推薦用synchronized:
synchronized(this){
number++;
}
3.synchronized和volatile比較
-
volatile不需要同步操作,所以效率更高,不會阻塞線程,但是適用情況比較窄
-
volatile讀變量相當於加鎖(即進入synchronized代碼塊),而寫變量相當於解鎖(退出synchronized代碼塊)
-
synchronized既能保證共享變量可見性,也可以保證鎖內操作的原子性;volatile只能保證可見性
4.ThreadLocal
ThreadLocal不是爲了解決多線程訪問共享變量,而是爲每個線程創建一個單獨的變量副本,提供了保持對象的方法和避免參數傳遞的複雜性。
顧名思義它是local variable(線程局部變量)。它的功用非常簡單,就是爲每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本衝突。從線程的角度看,就好像每一個線程都完全擁有該變量。(ThreadLocal採用了“以空間換時間”的方式)