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