1. 程式人生 > >簡單測試Java線程安全中阻塞同步與非阻塞同步性能

簡單測試Java線程安全中阻塞同步與非阻塞同步性能

訪問 完成 老師 system 測試 int oid 1.2 run

摘抄自周誌明老師的《深入理解Java虛擬機:JVM高級特性與最佳實踐》13.2.2 線程安全的實現方法

1.名詞解釋

同步是指鎖哥線程並發訪問共享數據時,保證共享數據同一時刻只被一個線程訪問

互斥同步(阻塞同步)是一種悲觀的並發策略,總是認為只要不去做正確的同步措施(加鎖),那就肯定會出現問題。

阻塞同步最主要的問題是進行線程阻塞和喚醒所帶來的性能問題,因為在JDK 1.2之後,Java的線程模型被替換為基於操作系統原生線程模型來實現,如要阻塞喚醒一個線程,都需要操作系統來幫忙完成,這就需要用戶態轉換到內核態,會耗費很多時間。

非阻塞同步:隨著硬件指令集的發展,我們有了另一種選擇:基於沖突檢測的樂觀並發策略,這種操作不需要掛起線程,會節省很多時間,比如CAS(compare and swap)指令。

2.開始測試

第一種加鎖方式:

    static int a=0;
    public static void lock() {
        Thread[] threads=new Thread[50];
        for(int i=0;i<threads.length;i++){
            threads[i]=new Thread(new Runnable() {
                
                @Override
                public void run() {
                    
for(int i=0;i<100000;i++){ synchronized(Main.class){ a++; } } } }); threads[i].start(); } while(Thread.activeCount() > 1){ Thread.yield(); } System.out.println(a); }

第二種CAS方式:

    static AtomicInteger integer=new AtomicInteger(0);
    public static void cas() {
        Thread[] threads=new Thread[50];
        for(int i=0;i<threads.length;i++){
            threads[i]=new Thread(new Runnable() {
                
                @Override
                public void run() {
                    for(int i=0;i<100000;i++){
                        integer.incrementAndGet();
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount() > 1){
            Thread.yield();
        }
        System.out.println(integer.get());
    }

3結論:運行兩個方法,同樣是50個線程,100000個自增,輸出時間差,可以看到性能之間的差異。

lock方法平均在1270ms

cas方法平均在175ms

可以看到阻塞同步與非阻塞同步之間巨大的差異,也可以看出Java線程用戶態內核態切換損耗的處理器時間很大。

簡單測試Java線程安全中阻塞同步與非阻塞同步性能