4.4 變量的線程安全分析 成員變量和靜態變量是否線程安全? 如果它們沒有共享,則線程安全
如果它們被共享了,根據它們的狀態是否能夠改變,又分兩種情況
如果只有讀操作,則線程安全
如果有讀寫操作,則這段代碼是臨界區,需要考慮線程安全
局部變量是否線程安全? 局部變量是線程安全的
但局部變量引用的對象則未必
如果該對象沒有逃離方法的作用訪問,它是線程安全的
如果該對象逃離方法的作用範圍,需要考慮線程安全
局部變量線程安全分析 public static void test1() { int i = 10; i++; } 一鍵獲取完整項目代碼 java 每個線程調用 test1() 方法時局部變量 i,會在每個線程的棧幀內存中被創建多份,因此不存在共享
public static void test1(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=1, args_size=0 0: bipush 10 2: istore_0 3: iinc 0, 1 6: return LineNumberTable: line 10: 0 line 11: 3 line 12: 6 LocalVariableTable: Start Length Slot Name Signature 3 4 0 i I 一鍵獲取完整項目代碼 java
如圖
局部變量的引用稍有不同
先看一個成員變量的例子
class ThreadUnsafe { ArrayList list = new ArrayList<>(); public void method1(int loopNumber) { for (int i = 0; i < loopNumber; i++) { // { 臨界區, 會產生競態條件 method2(); method3(); // } 臨界區 } } private void method2() { list.add("1"); } private void method3() { list.remove(0); } } 一鍵獲取完整項目代碼 java
執行
static final int THREAD_NUMBER = 2; static final int LOOP_NUMBER = 200; public static void main(String[] args) { ThreadUnsafe test = new ThreadUnsafe(); for (int i = 0; i < THREAD_NUMBER; i++) { new Thread(() -> { test.method1(LOOP_NUMBER); }, "Thread" + i).start(); } } 一鍵獲取完整項目代碼 java
其中一種情況是,如果線程2 還未 add,線程1 remove 就會報錯:
Exception in thread "Thread1" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.remove(ArrayList.java:496) at cn.itcast.n6.ThreadUnsafe.method3(TestThreadSafe.java:35) at cn.itcast.n6.ThreadUnsafe.method1(TestThreadSafe.java:26) at cn.itcast.n6.TestThreadSafe.lambda$main$0(TestThreadSafe.java:14) at java.lang.Thread.run(Thread.java:748) 一鍵獲取完整項目代碼 java 分析:
無論哪個線程中的 method2 引用的都是同一個對象中的 list 成員變量
method3 與 method2 分析相同
將 list 修改為局部變量
class ThreadSafe { public final void method1(int loopNumber) { ArrayList list) { list.remove(0); } } 一鍵獲取完整項目代碼 java
那麼就不會有上述問題了
分析:
list 是局部變量,每個線程調用時會創建其不同實例,沒有共享
而 method2 的參數是從 method1 中傳遞過來的,與 method1 中引用同一個對象
method3 的參數分析與 method2 相同
方法訪問修飾符帶來的思考,如果把 method2 和 method3 的方法修改為 public 會不會代理線程安全問題?
情況1:有其它線程調用 method2 和 method3
情況2:在 情況1 的基礎上,為 ThreadSafe 類添加子類,子類覆蓋 method2 或 method3 方法,
class ThreadSafe { public final void method1(int loopNumber) { ArrayList list) { new Thread(() -> { list.remove(0); }).start(); } } 一鍵獲取完整項目代碼 java
從這個例子可以看出 private 或 final 提供【安全】的意義所在,請體會開閉原則中的【閉】 ———————————————— 版權聲明:本文為CSDN博主「向着五星的方向」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/qq_69748833/article/details/136892005