一個線程中變數的修改可能不會立即對其他線程可見,事實上也許永遠不可見。 在代碼一中,如果一個線程調用了MyClass.loop(),將來的某個時間點,另一個線程調用了MyClass.setValue(100),第一個線程可能仍然不會終止,可能永遠迴圈下去 上面的問題有兩種解決辦法: 一是使用sync ...
一個線程中變數的修改可能不會立即對其他線程可見,事實上也許永遠不可見。
在代碼一中,如果一個線程調用了MyClass.loop(),將來的某個時間點,另一個線程調用了MyClass.setValue(100),第一個線程可能仍然不會終止,可能永遠迴圈下去
代碼一: public class MyClass{ private static final String TAG="MyClass"; private static int mValue=0; public static void setValue(int n){ mValue=n; } public static void loop(){ int value; while(value!=100){ try{ Log.i(TAG,"Value is "+value); Thread.sleep(1000); }catch(Exception e){ } } } }
上面的問題有兩種解決辦法:
一是使用synchronized關鍵字
public class MyClass{ private static final String TAG="MyClass"; private static int mValue=0; public static synchronized void setValue(int n){ mValue=n; } public static synchronized int getValue(){ return mValue; } public static void loop(){ int value; while((value=getValue())!=100){ try{ Log.i(TAG,"Value is "+value); Thread.sleep(1000); }catch(Exception e){ } } } }
二是使用volatile關鍵字
public class MyClass{ private static final String TAG="MyClass"; private static volatile int mValue=0;//添加volatile關鍵字 public static void setValue(int n){ mValue=n;//如果是mValue+=n,因為不是原子操作,還得使用synchronized } public static void loop(){ int value; while(value!=100){ try{ Log.i(TAG,"Value is "+value); Thread.sleep(1000); }catch(Exception e){ } } } }
value++不是原子的,value=1是原子的。volatile關鍵字只可以解決變數聲明是原子的那些併發問題,如果變數不是原子的就必須使用synchronized關鍵字
不要在synchronized塊中調用另一個對象的方法(它可能已經被鎖住並等待之前用到的對象解鎖),除非你能保證不會發生死鎖,通常情況下只有親手寫其他對象的類的代碼才敢確定不會發生死鎖。