1. 程式人生 > 其它 >多執行緒之原子類

多執行緒之原子類

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,還有AtomicBooleanAtomicIntegerArrayAtomicLongAtomicLongArray,對於引用型別,我們可以用AtomicReference,用法上都差不多。

前段時間,我們的線上系統就因為多執行緒使用i++導致線上資料表中的序號為空,最終的解決方法就是用AtomicInteger替換了Integer,如果後面各位小夥伴在實際開發過程中遇到類似的情況,可以考慮用原子類替換原有物件試下,說不定就解了你的燃眉之急。好了,今天的內容就到這裡吧!