成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

如何理解Java并發(fā)容器J.U.C

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

十載創(chuàng)新互聯(lián)網(wǎng)站建設(shè),由一走到現(xiàn)在,當中離不開團隊頑強的創(chuàng)業(yè)精神,離不開伴隨我們同行的客戶與專業(yè)的合作伙伴,創(chuàng)力信息一直秉承以“見一個客戶,了解一個行業(yè),交一個朋友”的方式為經(jīng)營理念,提出“讓每一個客戶成為我們的終身客戶”為目標,以為用戶提供精細化服務,全面滿足用戶需求為宗旨,誠信經(jīng)營,更大限度為用戶創(chuàng)造價值。期待邁向下一個更好的十載。

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

CopyOnWriteArrayList介紹

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

 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并發(fā)add時,復制多個副本,把數(shù)據(jù)搞亂。

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

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

> 如果出現(xiàn)并發(fā)get,會有以下3中情況。

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

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

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

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的時候需要拷貝原數(shù)組,如果原數(shù)組內(nèi)容比較多,比較大,可能會導致young gcfull gc。

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

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

  • CopyOnWriteArrayList由于add時需要復制數(shù)組,所以不適用高性能的互聯(lián)網(wǎng)的應用。

CopyOnWriteArraySet介紹

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

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

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.concurrent。ConcurrentSkipListSet<e>都是基于Map集合的,底層由ConcurrentSkipListMap實現(xiàn)。

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

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針對讀操作做了大量的優(yōu)化。在高并發(fā)場景很有優(yōu)勢。

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

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

> HashTable有很多的優(yōu)化空間,鎖住整個table這么粗暴的方法可以變相的柔和點,比如在多線程的環(huán)境下,對不同的數(shù)據(jù)集進行操作時其實根本就不需要去競爭一個鎖,因為他們不同hash值,不會因為rehash造成線程不安全,所以互不影響,這就是鎖分離技術(shù),將鎖的粒度降低,利用多個鎖來控制多個小的table,多線程訪問容器里不同數(shù)據(jù)段的數(shù)據(jù)時,線程間就不會存在鎖競爭,從而可以有效的提高并發(fā)訪問效率,這就是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內(nèi)部使用SkipList結(jié)構(gòu)實現(xiàn)。跳表是一個鏈表,但是通過跳躍式的查找方式使得插入,讀取數(shù)據(jù)時的時間復雜度變成O(log n)。

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

如何理解Java并發(fā)容器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支持高并發(fā),它的時間復雜度是log(N),和線程數(shù)無關(guān),也就是說任務一定的情況下,并發(fā)的線程越多,ConcurrentSkipListMap的優(yōu)勢就越能體現(xiàn)出來。

上述內(nèi)容就是如何理解Java并發(fā)容器J.U.C,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

當前名稱:如何理解Java并發(fā)容器J.U.C
網(wǎng)址分享:http://jinyejixie.com/article32/jjhjpc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計、Google、網(wǎng)站改版、網(wǎng)站維護、云服務器做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
灵石县| 宁都县| 黄浦区| 武乡县| 靖安县| 镇雄县| 迭部县| 徐汇区| 长泰县| 东乌珠穆沁旗| 吉木萨尔县| 饶平县| 饶平县| 卫辉市| 桃园县| 徐州市| 银川市| 清镇市| 深州市| 武隆县| 鹤岗市| 上思县| 孝义市| 成武县| 特克斯县| 隆昌县| 东乡族自治县| 汝阳县| 九龙坡区| 清河县| 沐川县| 临沧市| 迭部县| 丰宁| 曲麻莱县| 松阳县| 襄樊市| 安阳市| 高密市| 海安县| 枞阳县|