土耳其總統艾爾段:黑海再發現天然氣

摘錄自2020年10月17日中央通訊社土耳其報導

土耳其總統艾爾段今(17日)宣布,鑽井船征服者號在黑海又發現850億立方公尺天然氣儲量,使得已發現的黑海天然氣總量達4050億立方公尺。

艾爾段8月21日宣布,征服者號在北部岸外約100海里的黑海發現天然氣儲量達3200億立方公尺,目標於2023年開始對巿場供應黑海天然氣。

土耳其目前碳氫化合物能源需求幾乎完全仰賴進口,發現黑海天然氣可望提振政府財政,也有助舒緩經常對里拉匯率造成壓力的長期經常帳赤字。

能源轉型
國際新聞
土耳其
天然氣
黑海

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

躲得過走私、躲不過氣候變遷 尼泊爾境內印度犀面臨新威脅

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

中國喊2060碳排歸零 歐盟外長:應說明如何實現

摘錄自2020年10月24日中央通訊社報導

中國國家主席習近平9月22日在聯合國大會承諾,中國二氧化碳排放將在2030年前達到峰值,2060年前實現碳中和。

歐洲聯盟外長波瑞爾(Josep Borrell)10月22日在個人部落格發表文章,習近平已提出中國2060年前實現碳中和的承諾,加上歐洲正致力氣候外交,這可能是全球應對氣候變遷的重要轉折。他強調,雖然設定一個雄心勃勃的目標很重要,但更重要的是取得成果,而中國迄今尚未詳細說明要如何實現2060年的目標。中國在一帶一路倡議下,其中逾4成投資與能源建設相關,這導致化石燃料發電廠建設增加,這個議題應納入未來歐中對話的議程。

歐盟近年將應對氣候變遷推動為氣候多邊外交行動,歐中領導人今年9月視訊會議時,即強調中國是重要的全球合作夥伴,鼓勵中國加強氣候承諾、盡快啟動國家排放交易體系、設定氣候中和的目標,當時歐盟也強調,中國必須暫停在國外建設燃煤電廠和資助相關建設。

氣候變遷
循環經濟
國際新聞
中國
碳排放
碳中和
氣候外交
一帶一路

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

一篇文章快速搞懂 Atomic(原子整數/CAS/ABA/原子引用/原子數組/LongAdder)

前言

相信大部分開發人員,或多或少都看過或寫過併發編程的代碼。併發關鍵字除了Synchronized,還有另一大分支Atomic。如果大家沒聽過沒用過先看基礎篇,如果聽過用過,請滑至底部看進階篇,深入源碼分析。

提出問題:int線程安全嗎?

看過Synchronized相關文章的小夥伴應該知道其是不安全的,再次用代碼應驗下其不安全性:

public class testInt {
    static int number = 0;

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    number = number+1;
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();
        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();
        System.out.println("number:" + number);
    }
}

 

 

運行結果:

在上面的例子中,我們定義一個初始值為0的靜態變量number,再新建並運行兩個線程讓其各執行10萬次的自增操作,如果他是線程安全的,應該兩個線程執行后結果為20萬,但是我們發現最終的結果是小於20萬的,即說明他是不安全的。

在之前Synchronized那篇文章中說過,可以在number=number+1這句代碼上下加Synchronized關鍵字實現線程安全。但是其對資源的開銷較大,所以我們今天再看下另外一種實現線程安全的方法Atomic。

Atomic基礎篇分界線

原子整數(基礎類型)

整體介紹

Atomic是jdk提供的一系列包的總稱,這個大家族包括原子整數(AtomicInteger,AtomicLong,AtomicBoolean),原子引用(AtomicReference,AtomicStampedReference,AtomicMarkableReference),原子數組(AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray),更新器(AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater)。

AtomicInteger

AtomicInteger,AtomicBoolean,AtomicLong三者功能類似,咱就以AtomicInteger為主分析原子類。

先看下有哪些API,及其他們具體啥功能:

public class testInt {

    public static void main(String[] args) {
        //定義AtomicInteger類型的變量,值為1
        AtomicInteger i = new AtomicInteger(1);
        //incrementAndGet方法先新增1再返回,所以打印2,此時i為2
        System.out.println(i.incrementAndGet());
        //getAndIncrement方法先返回值再新增1,所以打印2,此時i為3
        System.out.println(i.getAndIncrement());
        //get方法返回當前i值,所以打印3,此時i為3
        System.out.println(i.get());
        //參數為正數即新增,getAndAdd方法先返回值再新增666,所以打印3,此時i為669
        System.out.println(i.getAndAdd(666));
        //參數為負數即減去,getAndAdd方法先返回值再減去1,所以打印669,此時i為668
        System.out.println(i.getAndAdd(-1));
        //參數為正數即新增,addAndGet方法先新增666再返回值,所以打印1334,此時i為1334
        System.out.println(i.addAndGet(666));
        //參數為負數即減去,addAndGet方法先減去-1再返回值,所以打印1333,此時i為1333
        System.out.println(i.addAndGet(-1));
        //getAndUpdate方法IntUnaryOperator參數是一個箭頭函數,後面可以寫任何操作,所以打印1333,此時i為13331
        System.out.println(i.getAndUpdate(x -> (x * 10 + 1)));
        //最終打印i為13331
        System.out.println(i.get());
    }
} 

 

 

執行結果:

對上述int類型的例子改進

public class testInt {
    //1.定義初始值為0的AtomicInteger類型變量number
    static AtomicInteger number = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    //2.調用incrementAndGet方法,實現加1操作
                    number.incrementAndGet();
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();
        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();
        System.out.println("number:" + number.get());
    }
}

 

 

我們可以看到運行結果是正確的20萬,說明AtomicInteger的確保證了線程安全性,即在多線程的過程中,運行結果還是正確的。但是這存在一個ABA問題,下面將原子引用的時候再說,先立個flag。

源碼分析

我們以incrementAndGet方法為例,看下底層是如何實現的,AtomicInteger類中的incrementAndGet方法調用了Unsafe類的getAndAddInt方法。

public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

 

我們看下getAndAddInt方法,裏面有個循環,直接值為compareAndSwapInt返回值為true,才結束循環。這裏就不得不提CAS,這就是多線程安全性問題的解決方法。

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
}

 

CAS

線程1和線程2同事獲取了主內存變量值0,線程1加1並寫入主內存,現在主內存變量值1,線程2也加2並嘗試寫入主內存,這個時候是不能寫入主內存的,因為會覆蓋掉線程1的操作,具體過程如下圖。

CAS是在線程2嘗試寫入內存的時候,通過比較並設置(CompareAndSet)發現現在主內存當前值為1,和他剛開始讀取的值0不一樣,所以他會放棄本次修改,重新讀取主內存的最新值,然後再重試下線程2的具體邏輯操作,再次嘗試寫入主內存。如果這時候線程1,再次對主內存進行了修改,線程2發現現在主內存的值又和預期不一樣,所以將放棄本次修改,再次讀取主內存最新值,再次重試並嘗試寫入主內存。我們可以發現這是一個重複比較的過程,即直到和預期初始值一樣,才會寫入主內存,否則將一直讀取重試的循環。這就是上面for循環的意義。

CAS的實現實際上利用了CPU指令來實現的,如果操作系統不支持CAS,還是會加鎖的,如果操作系統支持CAS,則使用原子性的CPU指令。

原子引用

在日常使用中,我們不止對上述基本類型進行原子操作,而是需要對一些複雜類型進行原子操作,所以需要AtomicReference。

不安全實現

先看不安全的BigDecimal類型:

public class testReference {
    static BigDecimal number = BigDecimal.ZERO;

    public static void main(String[] args) throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                   number=number.add(BigDecimal.ONE);
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();

        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();

        System.out.println(number);
    }
} 

 

 

運行結果如下圖,我們可以看到兩個線程,自循環1000次加1操作,最終結果應該是2000,可是結果小於2000。

安全實現-使用CAS

public class testReference {
    //定義AtomicReference類型BigDecimal變量
    static AtomicReference<BigDecimal> number = new AtomicReference<BigDecimal>(BigDecimal.ZERO);

    public static void main(String[] args) throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    //手動寫循環+CAS判斷
                    while(true){
                        BigDecimal pre=number.get();
                        BigDecimal next=number.get().add(BigDecimal.ONE);
                      if(number.compareAndSet(pre,next))  {
                          break;
                      }
                    }
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();

        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();

        System.out.println(number.get());

    }
}

 

 

運行結果如下:

ABA問題及解決

在上面CAS過程中,是通過值比較來知曉是不是能夠更新成功,那如果線程1先加1再減1,這樣主內存還是原來的值,即線程2還是可以更新成功的。但是這樣邏輯錯了,線程1已經發生了修改,線程2不能直接更新成功。

代碼:

public class testInt {

    static AtomicInteger number = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {


        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int a = number.get();
                System.out.println("開始number:" + a);
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(number.compareAndSet(a, a++));


            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("開始增加操作");
                int a = number.incrementAndGet();
                System.out.println("當前number:" + a);
                int b = number.decrementAndGet();
                System.out.println("當前number:" + b);
            }
        });
        t2.start();

        t1.join();
        t2.join();
    }
} 

 

 

我們看線程2對其進行了一系列操作,但是最後打印了還是true,表示可以更新成功的。這顯然不對。

那我們可以使用AtomicStampedReference,為其添加一個版本號。線程1在剛開始讀取主內存的時候,獲取到值為0,版本為1,線程2也獲取到這兩個值,線程1進行加1,減1的操作的時候,版本各加1,現在主內存的值為0,版本為2,而線程2還拿着預計值為0,版本為1的數據嘗試寫入主內存,這個時候因版本不同而更新失敗。具體我們用代碼試下:

public class testInt {

    static AtomicStampedReference<Integer> number = new AtomicStampedReference<Integer>(0, 0);

    public static void main(String[] args) throws Exception {


        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int a = number.getReference();
                int s = number.getStamp();
                System.out.println("開始number:" + a + ",stamp:" + s);
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(number.compareAndSet(a, a + 1, s, s + 1));


            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("開始增加操作");
                int a = number.getReference();
                int s = number.getStamp();
                number.compareAndSet(a, a + 1, s, s + 1);
                System.out.println("當前number:" + a + ",stamp:" + (s + 1));
                a = number.getReference();
                s = number.getStamp();
                number.compareAndSet(a, a - 1, s, s + 1);
                System.out.println("當前number:" + a + ",stamp:" + (s+1));
            }
        });
        t2.start();

        t1.join();
        t2.join();
    }
} 

 

我們可以看到每次操作都會更新stamp(版本號),在最後對比的時候不僅比較值,還比較版本號,所以是不能更新成功的,false.

原子數組

AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray三者類似,所以以AtomicIntegerArray為例,我們可以將下面AtomicIntegerArray看做是AtomicInteger類型的數組,其底層很類似,就不詳細寫了。

AtomicIntegerArray  array = new AtomicIntegerArray(10);
array.getAndIncrement(0);   // 將第0個元素原子地增加1

 

AtomicInteger[]  array = new AtomicInteger[10];
array[0].getAndIncrement();  // 將第0個元素原子地增加1

 

字段更新器和原子累加器比較簡單,這裏就不說了。 

Atomic進階篇分界線

LongAdder源碼分析

LongAdder使用

LongAdder是jdk1.8之後新加的,那為什麼要加他?這個問題,下面將回答,我們先看下如何使用。

public class testLongAdder {
    public static void main(String[] args) throws Exception {
        LongAdder number = new LongAdder();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int j = 0; j < 10000; j++) {
                    number.add(1L);
                }
            }
        };
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("number:" + number);
    }
}

 

我們可以看到LongAdder的使用和AtomicLong大致相同,使用兩個線程Thread1,Thread2對number值各進行一萬次的自增操作,最後的number是正確的兩萬。

與Atomic的對比優勢

那問題來了,既然AtomicLong能夠完成對多線程下的number進行線程安全的操作,那為什麼還要LongAdder?我們先來段代碼比較下,兩個在結果都是正確的前提下,性能方面的差距。

public class testLongAdder {
    public static void main(String[] args) {
       //1個線程,進行100萬次自增操作
        test1(1,1000000);
      //10個線程,進行100萬次自增操作
        test1(10,1000000);
     //100個線程,進行100萬次自增操作
        test1(100,1000000);
    }

    static void test1(int threadCount,int times){
        long startTime=System.currentTimeMillis();
        AtomicLong number1=new AtomicLong();
        List<Thread> threads1=new ArrayList<>();
        for(int i=0;i<threadCount;i++) {
            threads1.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < times; j++) {
                        number1.incrementAndGet();
                    }
                }
            }));
        }
        threads1.forEach(thread -> thread.start());
        threads1.forEach(thread ->{
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } );

        long endTime=System.currentTimeMillis();
        System.out.println("AtomicLong:"+number1+",time:"+(endTime-startTime));

        LongAdder number2=new LongAdder();
        List<Thread> threads2=new ArrayList<>();
        for(int i=0;i<threadCount;i++) {
            threads2.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < times; j++) {
                        number2.add(1);
                    }
                }
            }));
        }
        threads2.forEach(thread -> thread.start());
        threads2.forEach(thread ->{
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } );

        System.out.println("LongAdder:"+number2+",time:"+(System.currentTimeMillis()-endTime));

    }
} 

 

上述代碼對比了1個線程,10個線程,100個線程在進行100百次自增操作后,AtomicLong和LongAdder所花費的時間。通過打印語句,我們發現在最終number1和number2都正確的基礎上,LongAdder花費的時間比AtomicLong少了一個量級。

源碼分析

那為什麼會導致這種情況,我們就要從源碼層面分析。AtomicLong為什麼效率低?因為如果線程數量一多,尤其在高併發的情況下,比如有100個線程同時想要對對象進行操作,肯定只有一個線程會獲取到鎖,其他99個線程可能空轉,一直循環知道線程釋放鎖。如果該線程操作完畢釋放了鎖,其他99個線程再次競爭,也只有一個線程獲取鎖,另外98個線程還是空轉,直到鎖被釋放。這樣CAS操作會浪費大量資源在空轉上,從而使得AtomicLong在線程數越來越多的情況下越來越慢。

AtomicLong是多個線程對同一個value值進行操作,導致多個線程自旋次數太多,性能降低。而LongAdder在無競爭的情況,跟AtomicLong一樣,對同一個base進行操作,當出現競爭關係時則是採用化整為零的做法,從空間換時間,用一個數組cells,將一個value拆分進這個數組cells。多個線程需要同時對value進行操作時候,可以對線程id進行hash得到hash值,再根據hash值映射到這個數組cells的某個下標,再對該下標所對應的值進行自增操作。當所有線程操作完畢,將數組cells的所有值和無競爭值base都加起來作為最終結果。

我們先看下LongAdder裏面的字段,發現其裏面沒有,主要是在其繼承的Stripped64類中,有下面四個主要變量。

 /** CPU數量,即cells數組的最大長度*/
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    /**
     *cells數組,為2的冪,2,4,8,16.....,方便以後位運算
     */
    transient volatile Cell[] cells;

    /**
     * 基值,主要用於沒有競爭的情況,通過CAS更新。
     */
    transient volatile long base;

    /**
     * 調整單元格大小(擴容),創建單元格時使用的鎖。
     */
    transient volatile int cellsBusy;

 

 

下面是add方法開始。

 public void add(long x) {
        //as:cells數組的引用
        //b:base的基礎值
        //v:期望值
        //m:cells數組大小
        //a:當前數組命中的單元
        Cell[] as; long b, v; int m; Cell a;
        //as不為空(cells已經初始化過,說明之前有其他線程對初始化)或者CAS操作不成功(線程間出現競爭)
        if ((as = cells) != null || !casBase(b = base, b + x)) {
        //初始化uncontented,true表示未競爭(因為有兩個情況,這裏先初始化,後面對其修改,就能區分這兩種情況)
        boolean uncontended = true;
        //as等於null(cells未初始化)
        //或者線程id哈希出來的下標所對應的值為空(cell等於空),getProbe() & m功能是獲取下標,底層邏輯是位運算
        //或者更新失敗為false,即發生競爭,取非就為ture
        if (as == null || (m = as.length - 1) < 0 ||
                (a = as[getProbe() & m]) == null ||
                !(uncontended = a.cas(v = a.value, v + x)))
        //進入到if裏面,說明更新case失敗,或者更新某個cell也失敗了,或者cell為空,或者cells為空
                longAccumulate(x, null, uncontended);
        }
    }

 

從LongAdder調用Stripped64的longAccumulate方法,主要是初始化cellscells的擴容多個線程同時命中一個cell的競爭操作。

final void longAccumulate(long x, LongBinaryOperator fn,
                              boolean wasUncontended) {
        //x:add的值,fn:為null,wasUncontended:是否發生競爭,true為發生競爭,false為不發生競爭
        int h;//線程的hash值
        //如果該線程為0,即第一次進來,所以ThreadLocalRandom強制初始化線程id,再對其hash
        if ((h = getProbe()) == 0) {
            ThreadLocalRandom.current(); 
            h = getProbe();
            wasUncontended = true;
        }
        //擴容意向,為false肯定不擴容,為true可能擴容
        boolean collide = false; 
        //死循環               
        for (;;) {
            //as:cells數組的引用
            //a:當前線程命中的cell
            //n:cells的長度
            //v:當前線程命中的cell所擁有的value值
            Cell[] as; Cell a; int n; long v;
            //cells不為空
            if ((as = cells) != null && (n = as.length) > 0) {
                //當前線程命中的cell為空,下面邏輯是新增cell
                if ((a = as[(n - 1) & h]) == null) {
                    if (cellsBusy == 0) {       // Try to attach new Cell
                        Cell r = new Cell(x);   // Optimistically create
                        if (cellsBusy == 0 && casCellsBusy()) {
                            boolean created = false;
                            try {               // Recheck under lock
                                Cell[] rs; int m, j;
                                if ((rs = cells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            if (created)
                                break;
                            continue;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                }
                //發生競爭
                else if (!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                //沒有競爭,嘗試修改當前線程對應的cell值,成功跳出循環
                else if (a.cas(v = a.value, ((fn == null) ? v + x :
                                             fn.applyAsLong(v, x))))
                    break;
                //如果n大於CPU最大數量,不可擴容
                else if (n >= NCPU || cells != as)
                    collide = false;            // At max size or stale
                else if (!collide)
                    collide = true;
                //獲取到了鎖,進行擴容,為2的冪,
                else if (cellsBusy == 0 && casCellsBusy()) {
                    try {
                        if (cells == as) {      // Expand table unless stale
                            Cell[] rs = new Cell[n << 1];//左移一位運算符,數量加倍
                            for (int i = 0; i < n; ++i)
                                rs[i] = as[i];
                            cells = rs;
                        }
                    } finally {
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                h = advanceProbe(h);
            }
            //cells等於空,並且獲取到鎖,開始初始化工作,創建結束釋放鎖,繼續循環
            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
                boolean init = false;
                try {                           // Initialize table
                    if (cells == as) {
                        Cell[] rs = new Cell[2];
                        rs[h & 1] = new Cell(x);
                        cells = rs;
                        init = true;
                    }
                } finally {
                    cellsBusy = 0;
                }
                if (init)
                    break;
            }
            else if (casBase(v = base, ((fn == null) ? v + x :
                                        fn.applyAsLong(v, x))))
                break;                          // Fall back on using base
        }
    }

 

 

結語

結束了,撒花。這篇主要說了Atomic的一些使用,包括Atomic原子類(AtomicInteger,AtomicLong,AtomicBoolean),Atomic原子引用(AtomicReference,AtomicStampedReference),以及1.8之後LongAdder的優勢,源碼分析。過程還穿插了一些CAS,ABA問題引入和解決方式。

 

參考資料

Java多線程進階(十七)—— J.U.C之atomic框架:LongAdder

CAS原理

Java 8 Performance Improvements: LongAdder vs AtomicLong

AtomicInteger深入理解

原子操作類AtomicInteger詳解

玩轉Java併發工具,精通JUC,成為併發多面手

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

憋大招 陸風將推出全新概念車

此概念車採用了跨界車的設計風格,前臉的設計感較強,中網採用了較為規整的網格格柵,並且進氣格柵與兩側的大燈相連融會貫通,整體很有科技感。下方的霧燈區域,摒棄了傳統的矩形或圓形燈組造型,轉而採用誇張的C型設計,辨識度很強,同時周邊的線條設計也增強了運動感。

隨着國內汽車市場的發展,自主品牌近年在設計上的提升是我們有目共睹的。在本次廣州車展上,不少企業將推出“高顏值”的車型,而在眾多高顏值的車型中最為吸引眼球的是我們自主品牌陸風旗下的一款定位時尚跨界緊湊型SUV概念車。

眾多的“高顏”車型中為什麼只看上了陸風這款車?難不成這款車擁有傲視群雄的品質?先別急聽給你好好扒一扒,拋開品質的變化之大暫且不論,單就外觀的設計以及家族式風格的蛻變,就能很明顯得看出如今陸風品牌的設計能力和品牌變化的巨大。

外觀設計的成功意味着什麼?難道只是換一個設計師設計造型那麼簡單?其實不然,通過對外觀設計風格的變化,我們能看出一款車型品牌的壯大、車企對市場方向的把控能力、對潮流市場引領的方向,這絕對是值得我們關注和探究的。

說了“辣么多”我們還是聊回陸風這款顏值擔當吧。

這款定位為時尚跨界緊湊型SUV概念車,就是陸風將於廣州車展亮相的一款重磅車型,並計劃於明年正式投入生產。講真,在第一眼看見陸風的這一款概念車的時候,完全就是被它的車身側面造型所吸引過去的,全然不知這竟然是一款自主品牌的SUV。

此概念車採用了跨界車的設計風格,前臉的設計感較強,中網採用了較為規整的網格格柵,並且進氣格柵與兩側的大燈相連融會貫通,整體很有科技感。下方的霧燈區域,摒棄了傳統的矩形或圓形燈組造型,轉而採用誇張的C型設計,辨識度很強,同時周邊的線條設計也增強了運動感。配合時尚的保險杠設計,提升了整車的運動及越野氣質,讓人感覺“野性”十足。

如果車頭造型還沒能打動你,那車身側面一定能讓你心花怒放。側面大角度傾斜的後窗玻璃與發動機蓋隆起的線條,使得這款車頗具美系車的肌肉感,搭配上巨大的輪圈和貫穿全車的側面雙腰線的設計,為車身帶來了修長的視覺效果,真是非常符合像這樣的年輕人口味。

動力方面據本次車展工作人員透露,未來量產車型動力方面,其匹配的1.5T缸內直噴汽油引擎及最新一代CVT變速器,將帶來絕佳的駕駛體驗,將在明年下半年正式上市。

【點評】:在2016年各大自品牌都發力SUV市場的激烈競爭下,陸風X7能在眾多競品中突圍而出尤為難得。從陸風汽車的產品布局來看,現階段將全部精力都投放到SUV產品中來,從這款定位時尚跨界緊湊型SUV概念車的亮相足矣看出,這是陸風集團聚萬千心血於一身的產品。

同時也能從產品看出,陸風汽車是具有極強自主設計能力的車企,在這個“顏”字當先的時代,高顏值勢必會成為本次車展各類新車的大趨勢,而這款概念車無疑是此次車展的高顏者,有興趣的朋友可以到廣州車展現場,陸風展台(1.2號館 2A01展位),一睹這款概念車的靚相。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

realme 官方暗示 realme GT 系列 S888 新旗艦即將推出,傳聞偏遊戲取向、配備 125W 超級閃充和高螢幕更新率螢幕

一直以來,關於 realme 代號 Race 的全新旗艦系列的名稱就一直相當神秘,不過無論是從之前工信部曝光的手機外觀照片或者最近幾天 realme 高層的爆料,似乎都在暗示這款 realme 首款 S888 旗艦新機將以 realme GT 系列為名,從 Race 與 Nissan GT-R 、 Ford 之間以競速而生的形象,可預期除了擁有旗艦級的性能表現外,在螢幕更新率和快充方面也將令人驚豔。

▲圖片來源:TENAA

realme 官方暗示 realme GT 系列 S888 新旗艦即將推出,傳聞偏遊戲取向、配備 125W 超級閃充和高螢幕更新率螢幕

在小米11 已經在中國以及歐洲發表後,許多人也相當關心當初 realme 預告新旗艦將「首批」搭載 Qualcomm Snapdragon 888 旗艦行動平台的新機後續消息,當時 realme 賦予這款新旗艦 Race 的代號,但一直以來除了否認它是型號名稱外,對於這款 realme 新旗艦,官方就僅止於春節後會有進一步消息。

▲圖片來源:徐起Chase(微博)

不過隨著春節過完, realme 副總裁徐起日前也開始在微博針對這款新機進行預熱宣傳,從「東瀛戰神」 Nissan GT-R 到 Ford GT ,都正暗示著接下來 realme 全新旗艦系列將以 GT 為名:

▲圖片來源:徐起Chase(微博)

日前數碼閒聊站也在微博透露 realme GT 將於過年後登場,產品定位偏遊戲取取向,擁有高品質高螢幕更新率的平面螢幕、超級快充和 Snapdragon 888 的新旗艦,機身也相當輕薄。
按照過去的傳聞, realme GT 除了搭載高通 Snapdragon 888 旗艦行動平台,將配備 12GB RAM、256GB ROM ,同時可能搭載最高 160Hz 螢幕更新率和 realme 125W Ultra DART 超級閃充技術,並運行基於 Android 11 的 realme UI 2.0 操作系統。

▲圖片來源:數碼閒聊站(微博)

從前段時間在中國工信部的曝光的照片可以看到 realme GT 外觀在螢幕正面採用左上角採單挖孔的平面全螢幕設計,機身背面的主相機設計和目前多款 realme 雷同,不過在機身背面有著 GT 字樣。至於相機規格目前還無法得知,不過據過去傳聞將配備四鏡頭主相機設計:

▲圖片來源:TENAA

從機身側邊看來也相當輕薄:

▲圖片來源:TENAA

消息來源:徐起Chase(微博)|數碼閒聊站(微博)

延伸閱讀:
小米11 Lite 最新概念渲染圖曝光!主打輕薄、平面挖孔螢幕的小米11 平價版

realme V11 海外發表:搭載聯發科天璣 700 的輕薄大電量入門 5G 手機

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

傳聞 Apple 將於 3/16 舉行春季新品發表會,或將推出全新 iPad mini 和 AirTags 等新品

幾天前, Jon Prosser 才爆料 AirTags 和 iPad Pro 都將在 3 月登場,不過當時並未提及較確切的時間點。稍早來自另一名爆料者在 Twitter 引述的消息聲稱確認 Apple 春季新品發表會將在 3 月 16 日舉行,屆時也將帶來 AirTags 、 iPad mini 6 等新品。同時,最新爆料也指出 Apple Card 也將在這場活動宣佈支持更多國家和地區市場的支援。

傳聞 Apple 將於 3/16 舉行春季新品發表會,或將推出全新 iPad mini 和 AirTags 等新品

先前 Jon Prosser 曾爆料 iPad Pro 和 AirTags 將於 3 月發表,而稍早另一名爆料者 FrontTron 在 Twitter 引述 란즈크 (yeux1122) 在 NAVER 的爆料指出 Apple 傳聞即將在 3 月舉行春季新品發表會,時間將訂在 3 月 16 日。
針對這份爆料, FronTron 提到日期部分是相較肯定的,但新品部分則與過去的爆料有些不同,這次提到將發表的產品會有全新 iPad 、 iPad mini 、 AirTags ,另外 Apple Card 將支持更多國家和地區。

▲圖片來源:Tron (Twitter/ @FrontTron)

回顧去年 iPad Pro(2020)發表的時間也是落在 3 月中旬,確實時間部分是較有可能的。但像是爆料中提及的新品如 iPad 就不太可能會在今年 3 月就再次推出新版本,畢竟這款產品在去年 9 月才更新,同時在 MacRumors 的購買建議也還是處於建議可購買的狀態。

▲圖片來源:MacRumors

至於 iPad mini 在三月登場的可能性就相當大了,除了 Jon Prosser 或這次 Tron 等人的爆料, iPad mini 都即將推出 2021 年的全新版本,在 MacRumors 的購買建議也已呈現不建議購買(即將更新)的狀態。

▲圖片來源:MacRumors

回顧 2019 年 iPad mini(第 5 代) 的推出,搭載 A12 仿生晶片、 True Tone 顯示、藍牙 5.0 和支持 Apple Pencil ,不過根據傳聞將在今年 3 月再次推出全新版本。據悉新一代 iPad mini(第 6 代)將搭載 8.4 吋螢幕,透過減少螢幕邊框增加螢幕尺寸,其外觀與 iPad Air(第 3 代)有些相似,具備結合 Home 鍵的 Touch ID 以及 Lightning 接口。
▲圖片來源:MacRumors

至於全新 iPad Pro 將改採 mini LED 螢幕、搭載 5nm 製程的 A14X 仿生晶片,同時和 iPhone 12 系列一樣採用 Qualcomm Snapdragon X55 5G 連網數據晶片、支持 mmWave 毫米波和 6GHz 以下頻段,記憶體則有 6GB RAM。

▲圖片來源:MacRumors

消息來源:Tron (Twitter/ @FrontTron)|란즈크 (NAVER/ yeux1122)

延伸閱讀:
小米首款「四曲瀑布螢幕概念手機」正式亮相!四邊 88° 超曲面螢幕、螢幕下前鏡頭、整機一體無孔化設計

Redmi K40 / K40 Pro、小米10 新版本外觀認證照曝光

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

不再沒事就整新,iPhone 12 / 12 mini 將提供更多「原機維修」支援

曾拿 iPhone 進行像是背殼玻璃破損等的問題維修時,應該都會遇過一個狀況。直覺會認為應該可以原機修理的項目,卻發現依照蘋果的政策,幾乎都得要以整新的方式來處理。雖說整台換新可能有機會避開其他問題,但這樣遇到維修就必須要換機還是會為消費者帶來一定程度的麻煩。對此,據報蘋果最近向授權維修單位開始提供一個新的原機維修零件組,將可針對不少以往可能唯一選項就是整新的項目,為顧客的愛機提供真正的原機維修服務。繼續閱讀不再沒事就整新,iPhone 12 / 12 mini 將提供更多「原機維修」支援報導內文。

不再沒事就整新,iPhone 12 / 12 mini 將提供更多「原機維修」支援

據報自 2/23 起,蘋果原廠智慧型手機的原機維修支援項目,將在新的「iPhone Rear System」支援下,納入包括主機板、電池、Face ID 系統、外殼(包括背殼玻璃)、無線充電線組、Taptic Engine 觸覺震動引擎,等以往可能一遇到故障動不動就只能換機的維修項目。

▲圖片來源:Apple

也就是說,未來將可避免以往可能只因為背殼玻璃破裂就得要換整台機器的狀況。不過也不是所有項目皆可支援這樣的維修方式,技術文件顯示這次延伸的原機維修服務範圍,很可惜並不包含螢幕及主相機鏡組部分。也就是說,如果維修涉及這些項目就還是得要進行全機整新。

據外媒報導,只要是有在販售該款 iPhone 機型的國家就能支援這樣的新維修政策。內部文件更指,這樣為原機維修導入更多維修項目的政策,是 Apple 更致力減少碳足跡的做法之一。所以儘管現階段僅有 iPhone 12 與 iPhone 12 mini 加入提供這個新的原機維修項目支援(不支援 Pro 系列機型),但就該公司近年持續關注環保與永續發展相關項目的發展看來,估計未來應該會有更多機型也能提供這樣的維修新政才是。

本篇圖片 / 引用來源

延伸閱讀:

你的 Pixel 遇到主相機黑畫面無法啟動嗎?官方暗示可能為硬體問題

Gogoro 發表會邀請釋出,1 系列「混合」2 系列路線新車將登場?

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

疑似 Xperia 10 III 跑分現身 Geekbench 資料庫,將支持 5G、搭載高通 S765G處理器?

上個月我們曾分享過 OnLeaks 釋出的 Sony 新一代 Xperia 10 系列中階新機 Xperia 10 III 的外觀渲染圖,雖然在外觀方面和 Xperia 10 II 相比改變不大,不過傳聞將首次在 Xperia 10 系列中階幾種支持 5G 。日前在 Slashleaks 曝光一張 Geekbench 資料庫的裝置跑分,雖然關於它的處理器目前眾說紛紜,但可確定的是 Xperia 10 III 將是款 5G 手機。

▲圖片來源:OnLeaks(Voice)

疑似 Xperia 10 III 跑分現身 Geekbench 資料庫,將支持 5G、搭載高通 S765G處理器?

日前在 Slashleaks 曝光一張型號 SONY A003SO 裝置的 Geekbench 5 跑分數據,獲得單核跑分 601 分、多核跑分 1821 分的成績,由於高通 Snapdragon 690 和高通 Snapdragon 765G 過去在 Geekbench 5 的成績其實相當接近,因此目前關於 Xperia 10 III 會搭載哪一款處理器也有上述兩種說法。根據頁面的資料,這款疑似為 Xperia 10 III 的裝置搭載了一款代號「Lito」的 1.8GHz 八核心處理器、配備 6GB RAM ,推測較搭載高通 Snapdrgon 765G 的可能性較大。
▲圖片來源:Slashleaks

不過參考過去 Xperia 10 系列一直以來都是搭載高通 Snapdragon 6 系列處理器,例如 Xperia 10 搭載 Snapdragon 630 處理器、 Xperia 10 II 搭載 Snapdragon 665 處理器,若最終真的選擇定位相較 Snapdragon 690 更高一階的 Snapdragon 765G 處理器,加上從 4GB RAM 提升至 6GB RAM 、支援 5G 等規格配置上的升級,很可能也會讓 Xperia 10 III 有著相較前一代更高的售價。回顧 Xperia 10 II 建議售價 11,490 元,不知大家認為 Xperia 10 III 的價格會落在哪呢?

消息來源:GSMArena

延伸閱讀:
Sony Mobile 中階新機 Xperia 10 III 高清晰渲染圖曝光:外型與前代相似、仍將保留3.5mm耳機孔

Redmi Note 10 系列確定將於 3/4 全球發表,相機與螢幕為此次升級重點

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

亮相廣州車展,漢能全太陽能動力汽車“圈粉”無數

汽車儀錶盤和中控均採用了大屏設計,特別是中控懸浮的觸控大屏,使車輛內飾更顯輕盈,同時也使人機交流更加合理。愛車一族近距離觀察漢能全太陽能動力汽車。德國大眾工作人員在漢能太陽能汽車展台参觀交流。漢能控股高級副總裁張彬表示,隨着光伏技術的普及,未來砷化鎵薄膜太陽能芯片的成本會降到1美元/瓦,以一輛鋪設6平方米的太陽能板的汽車為例,成本僅比普通電動汽車增加1800美元(1。

11月18日,全球薄膜太陽能發電領軍企業漢能控股攜其首款全太陽能動力跑車——Hanergy Solar R亮相2016廣州國際車展,這是全球專業汽車展會上第一次出現有“終極新能源”之稱的太陽能汽車的身影。

本次廣州國際車展Hanergy Solar R的亮相吸引了很多相關人士的關注,包括汽車、能源等行業媒體,業內人士以及愛車一族。

其實早在今年的7月2日,漢能全太陽能動力汽車發布會上,漢能就已經亮出其四款全太陽能動力車,除了Hanergy Solar R,還有Hanergy Solar A、Hanergy Solar L以及Hanergy Solar O三款車型。

Hanergy Solar R是一款太陽能新能源跑車,前蓋、車頂和側面集成了柔性超薄的太陽能芯片,並和流線型車身完美地結成一體。

黑白分割的整體色彩,讓跑車更加動感。尾部和車頂一體的擾流設計,讓太陽能芯片面積最大化的同時,大幅降低了風阻係數和高速行駛的穩定性。

汽車儀錶盤和中控均採用了大屏設計,特別是中控懸浮的觸控大屏,使車輛內飾更顯輕盈,同時也使人機交流更加合理。

愛車一族近距離觀察漢能全太陽能動力汽車。

德國大眾工作人員在漢能太陽能汽車展台参觀交流。

漢能控股高級副總裁張彬表示,隨着光伏技術的普及,未來砷化鎵薄膜太陽能芯片的成本會降到1美元/瓦,以一輛鋪設6平方米的太陽能板的汽車為例,成本僅比普通電動汽車增加1800美元(1.2萬元人民幣),這僅相當於一輛普通汽油車一年的燃油費用。

“做老百姓能買得起的太陽能汽車”。未來太陽能汽車定位在高端車型的同時,也要立足普通家用車型,讓太陽能汽車絕不是富人的玩具,普通老百姓都可以體驗未來科技,享受綠色出行帶來的便利。

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?