最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java current并發(fā)包超詳細(xì)分析

 更新時(shí)間:2023年02月21日 10:13:33   作者:綠仔牛奶_  
current并發(fā)包、在JDK1.5之前Java并沒有提供線程安全的一些工具類去操作多線程,需要開發(fā)人員自行編寫實(shí)現(xiàn)線程安全,但仍然無法完全避免低性能、死鎖、資源管理等問題。在JDK1.5時(shí)新增了java.util.current并發(fā)包,其中提供了許多供我們使用的并發(fā)編程工具類

并發(fā)包

current并發(fā)包、在JDK1.5之前Java并沒有提供線程安全的一些工具類去操作多線程,需要開發(fā)人員自行編寫實(shí)現(xiàn)線程安全,但仍然無法完全避免低性能、死鎖、資源管理等問題。在JDK1.5時(shí)新增了java.util.current并發(fā)包,其中提供了許多供我們使用的并發(fā)編程工具類。本文對(duì)于典型的并發(fā)包做出講解

ConcurrentHashMap

Java集合框架提供了存儲(chǔ)容器HashMap用于存儲(chǔ)鍵值對(duì),但是HashMap是線程不安全的。在并發(fā)編程中,我們向HashMap添加大量數(shù)據(jù)時(shí),可能會(huì)出現(xiàn)各種預(yù)料之外的問題。

同時(shí)Java也提供了線程安全的集合類HashTable,打開HashTable的底層我們會(huì)發(fā)現(xiàn)HashTable的所有方法都利用synchtonized進(jìn)行了上鎖機(jī)制來保證了線程安全,但是利用這種阻塞同步的機(jī)制來保證線程安全的同時(shí)會(huì)大大降低程序的性能和執(zhí)行效率,這也是為什么HashTable被淘汰的原因

在JDK1.5之后Java就提供了保證性能高效、線程安全的鍵值對(duì)存儲(chǔ)容器ConcurrentHashMap

下面我們看下HashMap、HashTable、ConcurrentHashMap的對(duì)比

public class Demo01 {
    //public static Map<String,String> maps = new HashMap<String, String>();
    //public static Map<String,String> maps = new Hashtable<String, String>();
    public static Map<String,String> maps = new ConcurrentHashMap<String, String>();
    public static void main(String[] args) throws Exception {
        Runnable task = new Temp();
        Thread t1 = new Thread(task,"A線程");
        Thread t2 = new Thread(task,"B線程");
        t1.start();
        t2.start();
        // 保證t1和t2先執(zhí)行完
        t1.join();
        t2.join();
        System.out.println("最終集合長度:"+maps.size());
    }
}
class Temp implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 500000; i++) {
 Demo01.maps.put(Thread.currentThread().getName()+i,Thread.currentThread().getName()+i);
        }
    }
}

如上述代碼所示,我們啟動(dòng)兩條線程執(zhí)行同一任務(wù):向容器中添加50萬條數(shù)據(jù),預(yù)期最終容器中的數(shù)據(jù)將會(huì)達(dá)到100萬條。

利用HashMap存儲(chǔ)時(shí),發(fā)現(xiàn)程序會(huì)出現(xiàn)各種各樣的異常狀況

程序卡頓,不報(bào)異常也不停止

報(bào)異常

java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode

最終產(chǎn)生錯(cuò)誤數(shù)據(jù)

利用HashTable存儲(chǔ)時(shí),發(fā)現(xiàn)HashTable可以準(zhǔn)確存儲(chǔ)。并且對(duì)比HashTable和ConcurrentHashMap兩者的存儲(chǔ)速度,發(fā)現(xiàn)大差小不差甚至HashTable還要更快。那么為什么還要說HashTable效率低下呢?

是因?yàn)槲覀冎皇菧y(cè)試了對(duì)數(shù)據(jù)進(jìn)行的寫操作,而沒有測(cè)試其他的像查詢、修改等操作。綜合來講ConcurrentHashMap的各項(xiàng)性能優(yōu)于HashTbale,所以我們?cè)谛枰紤]線程安全時(shí),就可以采用ConcurrentHashMap進(jìn)行存儲(chǔ)數(shù)據(jù)

那么ConcurrentHashMap是如何既保證線程安全又不失高性能的存儲(chǔ)數(shù)據(jù)呢?

首先明確它的底層實(shí)現(xiàn)機(jī)制是用CAS機(jī)制+synchronized分段式鎖,屬于是悲觀和樂觀相結(jié)合

HashTable工作時(shí)會(huì)將整個(gè)哈希表進(jìn)行上鎖,此時(shí)所有其他線程都將被阻塞,效率低下

ConcurrentHashMap工作時(shí)利用synchronized進(jìn)行分段式上鎖,我們知道哈希表底層基于數(shù)組實(shí)現(xiàn),數(shù)組中每個(gè)位置形成槽位以便后續(xù)成鏈或者轉(zhuǎn)換樹結(jié)構(gòu)。而分段式上鎖就是將當(dāng)前線程所存儲(chǔ)的該位置進(jìn)行上鎖,其他位置仍可以被其他線程進(jìn)行操作。

CountDownLatch倒計(jì)數(shù)觸發(fā)

CountDownLatch同樣是current包下的一個(gè)同步工具,它的主要作用就是使當(dāng)前線程等待一條或多條線程執(zhí)行完畢后再執(zhí)行當(dāng)前線程。同時(shí)提供了兩個(gè)主要方法來控制線程的交替執(zhí)行

// 創(chuàng)建CountDownLatch
CountDownLatch cdl = new CountDownLatch(1);
cdl.await()// 讓出cpu,使當(dāng)前線程等待
cdl.CountDown() // 計(jì)數(shù)器減1,只有當(dāng)計(jì)數(shù)器為零時(shí)才會(huì)喚醒被await的線程

CountDownLatch提供了一個(gè)構(gòu)造器用于參數(shù)Count,在創(chuàng)建時(shí)就給定計(jì)數(shù)個(gè)數(shù)。每次調(diào)用CountDown方法就減一知道減為0時(shí)才會(huì)執(zhí)行被await等待的線程。

我們來看下面這個(gè)示例,目的是順序打印出“A、B、C”

public class Demo02 {
    public static void main(String[] args) {
        CountDownLatch count = new CountDownLatch(1);
        new ThreadA(count).start();
        new ThreadB(count).start();
    }
}
class ThreadA extends Thread{
    private CountDownLatch count;
    public ThreadA(CountDownLatch count) {
        this.count = count;
    }
    @Override
    public void run() {
        System.out.println("A");
        // 使當(dāng)前線程等待  等待打印B之后宰繼續(xù)執(zhí)行打印A
        try {
            count.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("C");
    }
}
class ThreadB extends Thread{
    private CountDownLatch count;
    public ThreadB(CountDownLatch count) {
        this.count = count;
    }
    @Override
    public void run() {
        System.out.println("B");
        // 當(dāng)前線程執(zhí)行完后倒計(jì)數(shù)減一
        count.countDown();
    }
}

但是有序線程執(zhí)行先后 順序不確定,也有可能打印出“B、A、C”

CyclicBarrier循環(huán)屏障

CyclicBarrier與CountDownLatch很容易弄混

CountDownLatch:使一條或多條線程等待其他線程執(zhí)行完畢之后再執(zhí)行自己,內(nèi)部使用倒計(jì)數(shù),最終執(zhí)行被await等待的線程

CyclicBarrier:阻塞一個(gè)線程組,內(nèi)部采用正計(jì)數(shù)。當(dāng)被阻塞的線程達(dá)到某個(gè)數(shù)量時(shí)才能執(zhí)行指定的任務(wù)。我們每調(diào)用一次await代表阻塞了一條線程。

假設(shè)示例:五個(gè)人進(jìn)入會(huì)議室執(zhí)行開會(huì)任務(wù)

// 六條線程:五個(gè)員工進(jìn)入會(huì)議室、一個(gè)開會(huì)
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        // 創(chuàng)建循環(huán)屏障
        CyclicBarrier cb = new CyclicBarrier(5,new Metting());
        for (int i = 1; i <= 4; i++) {
            new Employee(i+"號(hào)員工",cb).start();
        }
    }
}
class Employee extends Thread{
    private CyclicBarrier cb;
    public Employee(String s, CyclicBarrier cb) {
        super(s);
        this.cb = cb;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"進(jìn)入會(huì)議室");

        try {
            Thread.sleep(1000);
            cb.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class Metting implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"組織會(huì)議,會(huì)議開始");
    }
}

上述代碼所示:

CyclicBarrier cb = new CyclicBarrier(5,new Metting());

我們創(chuàng)建了一個(gè)循環(huán)屏障用于控制線程執(zhí)行,當(dāng)被await阻塞的線程數(shù)==5時(shí)將會(huì)執(zhí)行newMetting的Runnable線程任務(wù)

同時(shí)會(huì)發(fā)現(xiàn)最后一個(gè)到達(dá)會(huì)議室的人(線程)將會(huì)組織會(huì)議開始,這說明我們調(diào)用了await方法并不是將該線程阻塞。是由于CyclicBarrier底層由線程池實(shí)現(xiàn),每一條線程執(zhí)行完畢之后都會(huì)被線程池回收而不是阻塞

Semaphore指示燈

Semaphore用于設(shè)置一個(gè)或多個(gè)線程可以同時(shí)執(zhí)行即控制線程的并發(fā)數(shù)量,其他線程被阻塞。常用于限流操作。同時(shí)可以設(shè)置公平鎖和非公平鎖

Semaphore的使用與Lock工具有些類似,同樣是提供了兩個(gè)方法用于上鎖和解鎖。只是Semaphore可以自由的控制能拿到鎖的線程數(shù)

Semaphore提供了如下兩個(gè)構(gòu)造器

public Semaphore(int permits) // permits為允許執(zhí)行的線程數(shù)
public Semaphore(int permits, boolean fair)
    // fair為true表示公平鎖,等待時(shí)間最長的線程將在下次進(jìn)入 反之是不公平鎖

Semphore提供的兩個(gè)操作鎖方法

public void acquire()  // 表示獲得許可
public void release()  // 表示釋放許可

示例:

public class SemaphoreDemo {
    public static void main(String[] args) {
        // 創(chuàng)建任務(wù)
        Service service = new Service();
        for (int i = 1; i <= 5; i++) {
            new MyThread(i+"號(hào)線程",service).start();
        }
    }
}
// 線程類
class MyThread extends Thread{
    private Service service;
    public MyThread(String name,Service service){
        super(name);
        this.service = service;
    }
    @Override
    public void run() {
        try {
            service.testMethod();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
// 抽離業(yè)務(wù)代碼
class Service{
    // 創(chuàng)建Semaphore對(duì)象 并指定線程數(shù)
    private Semaphore sp = new Semaphore(2);
    public void testMethod() throws Exception {
        // 獲取許可
        sp.acquire();
        System.out.println(Thread.currentThread().getName()+"進(jìn)入  時(shí)間:"+System.currentTimeMillis());
        Thread.sleep(200);
        System.out.println(Thread.currentThread().getName()+"執(zhí)行成功");
        System.out.println(Thread.currentThread().getName()+"離開  時(shí)間:"+System.currentTimeMillis());
        // 釋放許可
        sp.release();
    }
}

如上述程序所示,我們?cè)趧?chuàng)建Semaphore時(shí)指定了允許的并發(fā)數(shù)量為2,那么業(yè)務(wù)代碼同時(shí)只能被兩個(gè)線程執(zhí)行,一旦一條線程執(zhí)行完畢之后將會(huì)釋放許可,立刻會(huì)有其他線程獲得許可進(jìn)入執(zhí)行

Exchanger交換者

Exchanger用于線程間的通信、數(shù)據(jù)交換。Exchanger提供了一個(gè)同步點(diǎn)exchange方法:public V exchange(V x)互相交換數(shù)據(jù)的兩條線程必須都運(yùn)行到了同步點(diǎn)才能執(zhí)行交換數(shù)據(jù)的操作,只有一方到達(dá)時(shí)就會(huì)進(jìn)行等待,等待時(shí)間可以由開發(fā)人員設(shè)定

我們先來看下面的示例

public class ExchangerDemo {
    public static void main(String[] args) {
        // 創(chuàng)建交換者
        Exchanger<String> exchanger = new Exchanger<>();
        // 創(chuàng)建兩條線程進(jìn)行交換數(shù)據(jù)
        new ThreadN("線程N(yùn)",exchanger).start();
        new ThreadP("線程P",exchanger).start();
    }
}
class ThreadN extends Thread{
    private Exchanger<String> exchanger;
    public ThreadN(String name,Exchanger<String> exchanger) {
        super(name);
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"給線程P:"+"我是線程N(yùn)");
        try {
            String exchange = exchanger.exchange("我是線程N(yùn)");
            System.out.println("線程N(yùn)拿到數(shù)據(jù):"+exchange);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
class ThreadP extends Thread{
    private Exchanger<String> exchanger;
    public ThreadP(String name,Exchanger<String> exchanger) {
        super(name);
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"給線程N(yùn):"+"我是線程P");
        try {
            String exchange = exchanger.exchange("我是線程P");
            System.out.println("線程P拿到數(shù)據(jù):"+exchange);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

根據(jù)最終打印,可以發(fā)現(xiàn)兩者交換了數(shù)據(jù)。這兩條線程擁有的是同一個(gè)交換者對(duì)象,所以可以實(shí)現(xiàn)數(shù)據(jù)交換。

前文提到過我們可以自定義線程等待的時(shí)間,就是再同步點(diǎn)exchange處等待另一條線程執(zhí)行到此的時(shí)間。利用exchange方法定義等待時(shí)間

public V exchange(V x, long timeout, TimeUnit unit)
    // timeout等待的時(shí)間數(shù)值  unit時(shí)間單位
    // 示例:只等待五秒
exchanger.exchange("111","5000", TimeUnit.SECONDS)

超出了規(guī)定的等待時(shí)間,正在等待的線程將被回收并拋出java.util.TimeoutException超時(shí)異常,所以交換數(shù)據(jù)的雙方必須都執(zhí)行到同步點(diǎn)才能進(jìn)行數(shù)據(jù)交換

到此這篇關(guān)于Java current并發(fā)包超詳細(xì)分析的文章就介紹到這了,更多相關(guān)Java current并發(fā)包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA2020.1創(chuàng)建springboot項(xiàng)目(國內(nèi)腳手架)安裝lombok

    IDEA2020.1創(chuàng)建springboot項(xiàng)目(國內(nèi)腳手架)安裝lombok

    這篇文章主要介紹了IDEA2020.1創(chuàng)建springboot項(xiàng)目(國內(nèi)腳手架)安裝lombok,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • java通過cglib動(dòng)態(tài)生成實(shí)體bean的操作

    java通過cglib動(dòng)態(tài)生成實(shí)體bean的操作

    這篇文章主要介紹了java通過cglib動(dòng)態(tài)生成實(shí)體bean的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 解析Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法

    解析Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法

    MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過程和高級(jí)映射的優(yōu)秀持久層框架,這篇文章主要介紹了Mybatis連續(xù)傳遞多個(gè)參數(shù)的方法,需要的朋友可以參考下
    2016-08-08
  • 關(guān)于IDEA的junit單元測(cè)試Scanner輸入不可用的問題(多種原因分析)

    關(guān)于IDEA的junit單元測(cè)試Scanner輸入不可用的問題(多種原因分析)

    IDEA在Junit測(cè)試中使用了Scanner,但是控制臺(tái)一直轉(zhuǎn)圈,無法輸入,eclipse默認(rèn)可用,其實(shí)解決方法很多,今天小編給大家分享多種問題原因分析及解決方法,感興趣的朋友一起看看吧
    2021-06-06
  • Java NIO.2 使用Path接口來監(jiān)聽文件、文件夾變化

    Java NIO.2 使用Path接口來監(jiān)聽文件、文件夾變化

    Java7對(duì)NIO進(jìn)行了大的改進(jìn),新增了許多功能,接下來通過本文給大家介紹Java NIO.2 使用Path接口來監(jiān)聽文件、文件夾變化 ,需要的朋友可以參考下
    2019-05-05
  • spring boot 日志配置詳解

    spring boot 日志配置詳解

    本篇文章主要介紹了spring boot 日志配置 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • 關(guān)于BeanUtils.copyProperties(source, target)的使用

    關(guān)于BeanUtils.copyProperties(source, target)的使用

    這篇文章主要介紹了關(guān)于BeanUtils.copyProperties(source, target)的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 基于UDP實(shí)現(xiàn)聊天室功能

    基于UDP實(shí)現(xiàn)聊天室功能

    這篇文章主要為大家詳細(xì)介紹了基于UDP實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • java編寫屬于自己的線程池

    java編寫屬于自己的線程池

    這篇文章主要為大家詳細(xì)介紹了java編寫屬于自己的線程池,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Java實(shí)現(xiàn)斷點(diǎn)下載功能的示例代碼

    Java實(shí)現(xiàn)斷點(diǎn)下載功能的示例代碼

    當(dāng)下載一個(gè)很大的文件時(shí),如果下載到一半暫停,如果繼續(xù)下載呢?斷點(diǎn)下載就是解決這個(gè)問題的。本文將用Java語言實(shí)現(xiàn)斷點(diǎn)下載,需要的可以參考一下
    2022-05-05

最新評(píng)論

宁明县| 保康县| 奎屯市| 海安县| 嘉禾县| 鲁山县| 雷波县| 汤原县| 清涧县| 聂拉木县| 伊通| 瑞金市| 通州市| 曲松县| 洞头县| 克东县| 汽车| 乐东| 溆浦县| 白玉县| 镇原县| 磴口县| 兴化市| 乌兰浩特市| 金门县| 冷水江市| 冷水江市| 深泽县| 屏东市| 黔南| 嘉定区| 恭城| 夏津县| 宁城县| 潜江市| 射阳县| 迁安市| 屯留县| 饶平县| 故城县| 洛阳市|