多執行緒之原子類
阿新 • • 發佈:2021-07-15
在java
多執行緒程式設計中,我們會經常遇到各種因為資料共享帶來的執行緒安全問題,為了解決這個問題,我們經常需要給方法或者部分程式碼加鎖,但是如果直接通過synchronized
這樣的關鍵字加鎖的話,效能不夠友好,雖然Lock
也可以解決這個問題,但是相比於無鎖程式設計,效能也是不夠友好,為了更好地解決這個問題,從jdk1.5
開始,官方為我們提供了一系列原子類,所以今天我們就來看下如何通過原子類來保證執行緒安全。
我們先看這樣一段程式碼:
public class Example extends Thread{ private int count = 0; public Example(String name) { super(); this.setName(name); } @Override public void run() { super.run(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("name: " + this.getName() + ", count: " + count++); } public static void main(String[] args) { Example a = new Example("A"); for (int i = 0; i < 50; i++) { new Thread(a, "t" + i).start(); } } }
這是一段典型的java
多執行緒共享變數的應用,如果執行上面的程式碼,多次執行很容易出現下面這種情況:
這種情況就是我們常說的執行緒安全問題,在實際應用中最常出現在我們業務程式碼生成序號的時候,為了解決這個問題,我們可以引入原子類,把程式碼中做如下調整即可:
public class Example extends Thread{ private final AtomicInteger count = new AtomicInteger(0); public Example(String name) { super(); this.setName(name); } @Override public void run() { super.run(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("name: " + this.getName() + ", count: " + count.getAndAdd(1)); } public static void main(String[] args) { Example a = new Example("A"); for (int i = 0; i < 50; i++) { new Thread(a, "t" + i).start(); } } }
修改之後執行你會發現,不論你執行多少次,都不會出現資料重複的問題(執行緒安全),這種方式的好處是,既不影響原有程式碼的效能,又確保了執行緒安全:
除了AtomicInteger
,還有AtomicBoolean
、AtomicIntegerArray
、AtomicLong
、AtomicLongArray
,對於引用型別,我們可以用AtomicReference
,用法上都差不多。
前段時間,我們的線上系統就因為多執行緒使用i++
導致線上資料表中的序號為空,最終的解決方法就是用AtomicInteger
替換了Integer
,如果後面各位小夥伴在實際開發過程中遇到類似的情況,可以考慮用原子類替換原有物件試下,說不定就解了你的燃眉之急。好了,今天的內容就到這裡吧!