什么是線程的安全問題?
上一篇 Java基礎-多線程-①線程的創建和啟動 我們說使用實現Runnable接口的方式來創建線程,可以實現多個線程共享資源:
1 class Dog implements Runnable { 2 // 定義線程共享數據 3 private int t = 100; 4 5 @Override 6 public void run() { 7 // TODO:死循環,暫不處理 8 while (true) { 9 if (t > 0) { 10 11 System.out.println("當前線程:" + Thread.currentThread().getName() + "---" + t--); 12 } 13 } 14 } 15 } 16 17 public class ThreadDemo { 18 public static void main(String[] args) { 19 System.out.println("當前線程:" + Thread.currentThread().getName()); 20 Dog dog = new Dog(); 21 22 Thread thread = new Thread(dog); 23 Thread thread2 = new Thread(dog); 24 thread.start(); 25 thread2.start(); 26 27 } 28 }
開啟兩個線程,共享數據t=100,執行run方法中的代碼:當t大於0時,打印t--。分析一下可能會存在的問題:
因為CPU時間片快速切換的不確定性,該問題不一定會發生,為了模擬一下該問題的發生,在打印語句執行前,讓線程睡眠0.1秒:
1 @Override 2 public void run() { 3 while (true) { 4 if (t > 0) { 5 try { 6 Thread.sleep(100); 7 System.out.println("當前線程:" + Thread.currentThread().getName() + "---" + t--); 8 } catch (InterruptedException e) { 9 //TODO:暫不處理異常 10 } 11 } 12 } 13 }
問題產生的原因
首先我們想到是因為兩個線程共享了數據t。如果多個線程不涉及數據共享,各自執行自己的代碼,就不會出現這個問題。在線程不安全的單例模式中,就涉及到這個問題。
①多個線程共享了數據。
如果我們不判斷t>0,直接打印t--,或者只判斷t>0,不執行t--,只要循環不結束,程序不終止,從邏輯上來說,程序也沒有問題
②在線程任務中設計對共享數據的操作(這里的操作包括①判斷t>0;②執行t--),一個線程在操作共享數據的時候,其他的線程也操作了共享數據。
這時候就可能造成數據出錯。
總結來說,多個線程在執行同一段代碼的時候,每次的執行結果和單線程執行的結果都是一樣的,不存在執行結果的二義性,就可以稱作是線程安全的。線程安全問題多是由全局變量和靜態變量引起的,當多個線程對共享數據只執行讀操作,不執行寫操作時,一般是線程安全的;當多個線程都執行寫操作時,需要考慮線程同步來解決線程安全問題。