亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Java并發容器J.U.C

發布時間:2021-11-20 14:54:34 來源:億速云 閱讀:150 作者:柒染 欄目:云計算

本篇文章為大家展示了如何理解Java并發容器J.U.C,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

> J.U.Cjava.util.concurrent的簡寫,里面提供了很多線程安全的集合。

CopyOnWriteArrayList介紹

> CopyOnWriteArrayList相比于ArrayList是線程安全的,字面意思是寫操作時復制CopyOnWriteArrayList使用寫操作時復制技術,當有新元素需要加入時,先從原數組拷貝一份出來。然后在新數組里面加鎖添加,添加之后,將原來數組的引用指向新數組。

 public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock(); //加鎖
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            //引用指向更改
            setArray(newElements);
            return true;
        } finally {
            lock.unlock(); //釋放鎖
        }
    }

> 從上面的源碼中得到CopyOnWriteArrayListadd操作是在加鎖的保護下完成的。加鎖是為了多線程對CopyOnWriteArrayList并發add時,復制多個副本,把數據搞亂。

public E get(int index) {
        return get(getArray(), index);
}

> 以上代碼顯示get是沒有加鎖的

> 如果出現并發get,會有以下3中情況。

  • 如果寫操作未完成,那么直接讀取原數組的數據;

  • 如果寫操作完成,但是引用還未指向新數組,那么也是讀取原數組數據;

  • 如果寫操作完成,并且引用已經指向了新的數組,那么直接從新數組中讀取數據。

CopyOnWriteArrayList多線程代碼演示。

package com.rumenz.task;

import java.util.List;
import java.util.concurrent.*;


//線程安全
public class CopyOnWrireArrayListExample {

    public static Integer clientTotal=5000;
    public static Integer threadTotal=200;

   private static List<integer> list=new CopyOnWriteArrayList();

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore=new Semaphore(threadTotal);
        final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
        for (int i = 0; i &lt; clientTotal; i++) {
            final Integer j=i;
            executorService.execute(()-&gt;{
                try{
                    semaphore.acquire();
                    update(j);
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
                countDownLatch.countDown();

            });


        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("size:"+list.size());
    }

    private static void update(Integer j) {
        list.add(j);
    }
}

//size:5000

CopyOnWriteArrayList使用場景

  • 由于在add的時候需要拷貝原數組,如果原數組內容比較多,比較大,可能會導致young gcfull gc

  • 不能用于實時讀的場景,像拷貝數組,新增元素都需要時間,所以調用get操作后,有可能得到的數據是舊數據,雖然CopyOnWriteArrayList能做到最終一致性,但是沒有辦法滿足實時性要求。

  • CopyOnWriteArrayList適合讀多寫少的場景,比如白名單,黑名單等場景

  • CopyOnWriteArrayList由于add時需要復制數組,所以不適用高性能的互聯網的應用。

CopyOnWriteArraySet介紹

public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<e>();
}

> CopyOnWriteArraySet底層是用CopyOnWriteArraySet來實現的。可變操作(add,set,remove等)都需要拷貝原數組進行操作,一般開銷很大。迭代器支持hasNext(),netx()等不可變操作,不支持可變的remove操作,使用迭代器速度很快,并且不會與其它線程沖突,在構造迭代器時,依賴不變的數組快照。

CopyOnWriteArraySet多線代碼演示

package com.rumenz.task;

import java.util.List;
import java.util.Set;
import java.util.concurrent.*;


//線程安全
public class CopyOnWrireArraySetExample {

    public static Integer clientTotal=5000;
    public static Integer threadTotal=200;

   private static Set<integer> set=new CopyOnWriteArraySet();

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore=new Semaphore(threadTotal);
        final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
        for (int i = 0; i &lt; clientTotal; i++) {
            final Integer j=i;
            executorService.execute(()-&gt;{
                try{
                    semaphore.acquire();
                    update(j);
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
                countDownLatch.countDown();

            });


        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("size:"+set.size());
    }

    private static void update(Integer j) {
        set.add(j);
    }
}
//size:5000

CopyOnWriteArraySet使用場景

  • 適用于set大小一般很小,讀操作遠遠多于寫操作的場景

ConcurrentSkipListSet

public ConcurrentSkipListSet() {
     m = new ConcurrentSkipListMap<e,object>();
}

> ConcurrentSkipListSet<e>jdk6新增的類,支持自然排序,位于java.util.concurrentConcurrentSkipListSet<e>都是基于Map集合的,底層由ConcurrentSkipListMap實現。

> 在多線程環境下,ConcurrentSkipListSet<e>add,remove,contains是線程安全的。但是對于批量操作addAll,removeAll,containsAll并不能保證原子操作,所以是線程不安全的,原因是addAll,removeAll,containsAll底層調用的還是add,remove,contains方法,在批量操作時,只能保證每一次的add,remove,contains是原子性的(即在進行add,remove,contains,不會被其它線程打斷),而不能保證每一次批量操作都不會被其它線程打斷,因此在addAllremoveAllretainAllcontainsAll操作時,需要添加額外的同步操作。

public boolean addAll(Collection<!--? extends E--> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
}

public boolean removeAll(Collection<!--?--> c) {
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<!--?--> it = iterator();
        while (it.hasNext()) {
            if (c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
}

public boolean containsAll(Collection<!--?--> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
}

ConcurrentSkipListSet代碼演示

package com.rumenz.task;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;


//線程安全
public class CopyOnWrireArrayListExample {

    public static Integer clientTotal=5000;
    public static Integer threadTotal=200;

    private static Set<integer> set= new ConcurrentSkipListSet();

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore=new Semaphore(threadTotal);
        final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
        for (int i = 0; i &lt; clientTotal; i++) {
            final Integer j=i;
            executorService.execute(()-&gt;{
                try{
                    semaphore.acquire();
                    update(j);
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
                countDownLatch.countDown();

            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("size:"+set.size());
    }


    private static void update(Integer r) {
        set.add(r);
    }
}

//size:5000

ConcurrentHashMap

> ConcurrentHashMapkeyvalue都不允許為null,ConcurrentHashMap針對讀操作做了大量的優化。在高并發場景很有優勢。

> 在多線程環境下,使用HashMap進行put操作會引起死循環,導致CPU利用率到100%,所以在多線程環境不能隨意使用HashMap。原因分析:HashMap在進行put的時候,插入的元素超過了容量就會發生rehash擴容,這個操作會把原來的元素hash到新的擴容新的數組,在多線程情況下,如果此時有其它線程在進行put操作,如果Hash值相同,可能出現在同一數組下用鏈表表示,造成閉環,導致get的時候出現死循環,所以是線程不安全的。

> HashTable它是線程安全的,它涉及到多線程的操作都synchronized關鍵字來鎖住整個table,這就意味著所有的線程都在競爭同一把鎖,在多線程環境下是安全的,但是效率很低。

> HashTable有很多的優化空間,鎖住整個table這么粗暴的方法可以變相的柔和點,比如在多線程的環境下,對不同的數據集進行操作時其實根本就不需要去競爭一個鎖,因為他們不同hash值,不會因為rehash造成線程不安全,所以互不影響,這就是鎖分離技術,將鎖的粒度降低,利用多個鎖來控制多個小的table,多線程訪問容器里不同數據段的數據時,線程間就不會存在鎖競爭,從而可以有效的提高并發訪問效率,這就是ConcurrentHashMapJDK1.7版本的核心思想。

ConcurrentHashMap代碼演示案例

package com.rumenz.task;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;


//線程安全
public class ConcurrentHashMapExample {

    public static Integer clientTotal=5000;
    public static Integer threadTotal=200;

   private static Map<integer,integer> map=new ConcurrentHashMap<integer,integer>();

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore=new Semaphore(threadTotal);
        final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
        for (int i = 0; i &lt; clientTotal; i++) {
            final Integer j=i;
            executorService.execute(()-&gt;{
                try{
                    semaphore.acquire();
                    update(j);
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
                countDownLatch.countDown();

            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("size:"+map.size());
    }

    private static void update(Integer j) {
        map.put(j, j);
    }
}
//size:5000

ConcurrentSkipListMap

> ConcurrentSkipListMap內部使用SkipList結構實現。跳表是一個鏈表,但是通過跳躍式的查找方式使得插入,讀取數據時的時間復雜度變成O(log n)

> 跳表(SkipList):使用空間換時間的算法,令鏈表的每個結點不僅記錄next結點位置,還可以按照level層級分別記錄后繼第level個結點。

如何理解Java并發容器J.U.C

ConcurrentSkipListMap代碼案例

package com.rumenz.task;

import java.util.Map;
import java.util.concurrent.*;


//線程安全
public class ConcurrentSkipListMapExample {

    public static Integer clientTotal=5000;
    public static Integer threadTotal=200;

   private static Map<integer,integer> map=new ConcurrentSkipListMap&lt;&gt;();

    public static void main(String[] args) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore=new Semaphore(threadTotal);
        final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);
        for (int i = 0; i &lt; clientTotal; i++) {
            final Integer j=i;
            executorService.execute(()-&gt;{
                try{
                    semaphore.acquire();
                    update(j);
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
                countDownLatch.countDown();

            });


        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("size:"+map.size());
    }

    private static void update(Integer j) {
        map.put(j, j);
    }
}

//size:5000

ConcurrentHashMapConcurrentSkipListMap的對比

  • ConcurrentHashMapConcurrentSkipListMap性能要好一些。

  • ConcurrentSkipListMapkey是有序的,ConcurrentHashMap做不到。

  • ConcurrentSkipListMap支持高并發,它的時間復雜度是log(N),和線程數無關,也就是說任務一定的情況下,并發的線程越多,ConcurrentSkipListMap的優勢就越能體現出來。

上述內容就是如何理解Java并發容器J.U.C,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

桦甸市| 安国市| 四会市| 临夏县| 克什克腾旗| 太保市| 固安县| 卓尼县| 灵宝市| 论坛| 墨玉县| 定边县| 济阳县| 武平县| 扶风县| 浦东新区| 库车县| 洛阳市| 基隆市| 烟台市| 天全县| 北辰区| 华容县| 贡觉县| 达日县| 阿城市| 铁岭县| 嘉荫县| 辽阳县| 鄂尔多斯市| 陵川县| 磐石市| 高雄市| 宜宾县| 泸溪县| 丽水市| 霍林郭勒市| 玉屏| 泗水县| 乌拉特前旗| 青龙|