JDK中Atomic開頭的原子類實現原子性的原理是什么?


  • JDK Atomic開頭的類,是通過 CAS 原理解決並發情況下原子性問題。
  • CAS 包含 3 個參數,CAS(V, E, N)。V 表示需要更新的變量,E 表示變量當前期望值,N 表示更新為的值。只有當變量 V 的值等於 E 時,變量 V 的值才會被更新為 N。如果變量 V 的值不等於 E ,說明變量 V 的值已經被更新過,當前線程什么也不做,返回更新失敗。
  • 當多個線程同時使用 CAS 更新一個變量時,只有一個線程可以更新成功,其他都失敗。失敗的線程不會被掛起,可以繼續重試 CAS,也可以放棄操作。
  • CAS 操作的原子性是通過 CPU 單條指令完成而保障的。JDK 中是通過 Unsafe 類中的 API 完成的。
  • 在並發量很高的情況,會有大量 CAS 更新失敗,所以需要慎用。

 

未使用原子類,測試代碼

package constxiong.interview;
 
/**
 * JDK 原子類測試
 * @author ConstXiong
 * @date 2019-06-11 11:22:01
 */
public class TestAtomic {
 
    private int count = 0;
    
    public int getAndIncrement() {
        return count++;
    }
    
//    private AtomicInteger count = new AtomicInteger(0);
//    
//    public int getAndIncrement() {
//        return count.getAndIncrement();
//    }
    
    public static void main(String[] args) {
        final TestAtomic test = new TestAtomic();
        for (int i = 0; i <3; i++) {
            new Thread(){
                @Override
                public void run() {
                    for (int j = 0; j <10; j++) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " 獲取遞增值:" + test.getAndIncrement());
                    }
                }
            }.start();
        }
    }
    
    
}

 

打印結果中,包含重復值

Thread-0 獲取遞增值:1
Thread-2 獲取遞增值:2
Thread-1 獲取遞增值:0
Thread-0 獲取遞增值:3
Thread-2 獲取遞增值:3
Thread-1 獲取遞增值:3
Thread-2 獲取遞增值:4
Thread-0 獲取遞增值:5
Thread-1 獲取遞增值:5
Thread-1 獲取遞增值:6
Thread-2 獲取遞增值:8
Thread-0 獲取遞增值:7
Thread-1 獲取遞增值:9
Thread-0 獲取遞增值:10
Thread-2 獲取遞增值:10
Thread-0 獲取遞增值:11
Thread-2 獲取遞增值:13
Thread-1 獲取遞增值:12
Thread-1 獲取遞增值:14
Thread-0 獲取遞增值:14
Thread-2 獲取遞增值:14
Thread-1 獲取遞增值:15
Thread-2 獲取遞增值:15
Thread-0 獲取遞增值:16
Thread-1 獲取遞增值:17
Thread-0 獲取遞增值:19
Thread-2 獲取遞增值:18
Thread-0 獲取遞增值:20
Thread-1 獲取遞增值:21
Thread-2 獲取遞增值:22

 

測試代碼修改為原子類

package constxiong.interview;
 
import java.util.concurrent.atomic.AtomicInteger;
 
/**
 * JDK 原子類測試
 * @author ConstXiong
 * @date 2019-06-11 11:22:01
 */
public class TestAtomic {
 
//    private int count = 0;
//    
//    public int getAndIncrement() {
//        return count++;
//    }
    
    private AtomicInteger count = new AtomicInteger(0);
    
    public int getAndIncrement() {
        return count.getAndIncrement();
    }
    
    public static void main(String[] args) {
        final TestAtomic test = new TestAtomic();
        for (int i = 0; i <3; i++) {
            new Thread(){
                @Override
                public void run() {
                    for (int j = 0; j <10; j++) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " 獲取遞增值:" + test.getAndIncrement());
                    }
                }
            }.start();
        }
    }
    
    
}

 

打印結果中,不包含重復值

Thread-0 獲取遞增值:1
Thread-2 獲取遞增值:2
Thread-1 獲取遞增值:0
Thread-0 獲取遞增值:3
Thread-1 獲取遞增值:4
Thread-2 獲取遞增值:5
Thread-0 獲取遞增值:6
Thread-1 獲取遞增值:7
Thread-2 獲取遞增值:8
Thread-0 獲取遞增值:9
Thread-2 獲取遞增值:10
Thread-1 獲取遞增值:11
Thread-0 獲取遞增值:12
Thread-1 獲取遞增值:13
Thread-2 獲取遞增值:14
Thread-0 獲取遞增值:15
Thread-1 獲取遞增值:16
Thread-2 獲取遞增值:17
Thread-0 獲取遞增值:18
Thread-1 獲取遞增值:19
Thread-2 獲取遞增值:20
Thread-0 獲取遞增值:21
Thread-2 獲取遞增值:23
Thread-1 獲取遞增值:22
Thread-0 獲取遞增值:24
Thread-1 獲取遞增值:25
Thread-2 獲取遞增值:26
Thread-0 獲取遞增值:27
Thread-2 獲取遞增值:28
Thread-1 獲取遞增值:29


原文鏈接
 


 

所有資源資源匯總於公眾號



 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM