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

Java中常見的并發(fā)控制手段淺析

 更新時(shí)間:2021年08月13日 09:53:25   作者:一灰灰  
所謂并發(fā)控制就是幫助我們程序員更容易的讓線程之間合作,讓線程之間相互配合來(lái)滿足業(yè)務(wù)邏輯,這篇文章主要給大家介紹了關(guān)于Java中常見的并發(fā)控制手段的相關(guān)資料,需要的朋友可以參考下

前言

單實(shí)例的并發(fā)控制,主要是針對(duì)JVM內(nèi),我們常規(guī)的手段即可滿足需求,常見的手段大概有下面這些

  • 同步代碼塊
  • CAS自旋
  • 阻塞隊(duì)列,令牌桶等

1.1 同步代碼塊

通過(guò)同步代碼塊,來(lái)確保同一時(shí)刻只會(huì)有一個(gè)線程執(zhí)行對(duì)應(yīng)的業(yè)務(wù)邏輯,常見的使用姿勢(shì)如下

public synchronized doProcess() {
    // 同步代碼塊,只會(huì)有一個(gè)線程執(zhí)行
}

一般推薦使用最小區(qū)間使用原則,盡量不要直接在方法上加synchronized,比如經(jīng)典的雙重判定單例模式

public class Single {
  private static volatile Single instance;
  private Single() {}
  public static Single getInstance() {
      if (instance == null) {
          synchronized(Single.class) {
              if (instance == null) instance = new Single();
          }
      }
      return instance;
  }
}

1.2 CAS自旋方式

比如AtomicXXX原子類中的很多實(shí)現(xiàn),就是借助unsafe的CAS來(lái)實(shí)現(xiàn)的,如下

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


// unsafe 實(shí)現(xiàn)
// cas + 自選,不斷的嘗試更新設(shè)置,直到成功為止
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;
}

1.3 鎖

jdk本身提供了不少的鎖,為了實(shí)現(xiàn)單實(shí)例的并發(fā)控制,我們需要選擇寫鎖;如果支持多讀,單實(shí)例寫,則可以考慮讀寫鎖;一般使用姿勢(shì)也比較簡(jiǎn)單

private void doSome(ReentrantReadWriteLock.WriteLock writeLock) {
    try {
        writeLock.lock();
        System.out.println("持有鎖成功 " + Thread.currentThread().getName());
        Thread.sleep(1000);
        System.out.println("執(zhí)行完畢! " + Thread.currentThread().getName());
        writeLock.unlock();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void lock() throws InterruptedException {
    ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    new Thread(()->doSome(reentrantReadWriteLock.writeLock())).start();
    new Thread(()->doSome(reentrantReadWriteLock.writeLock())).start();
    new Thread(()->doSome(reentrantReadWriteLock.writeLock())).start();

    Thread.sleep(20000);
}

1.4 阻塞隊(duì)列

借助同步阻塞隊(duì)列,也可以實(shí)現(xiàn)并發(fā)控制的效果,比如隊(duì)列中初始化n個(gè)元素,每次消費(fèi)從隊(duì)列中獲取一個(gè)元素,如果拿不到則阻塞;執(zhí)行完畢之后,重新塞入一個(gè)元素,這樣就可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單版的并發(fā)控制

demo版演示,下面指定隊(duì)列長(zhǎng)度為2,表示最大并發(fā)數(shù)控制為2;設(shè)置為1時(shí),可以實(shí)現(xiàn)單線程的訪問(wèn)控制

AtomicInteger cnt = new AtomicInteger();

private void consumer(LinkedBlockingQueue<Integer> queue) {
    try {
        // 同步阻塞拿去數(shù)據(jù)
        int val = queue.take();
        Thread.sleep(2000);
        System.out.println("成功拿到: " + val + " Thread: " + Thread.currentThread());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        // 添加數(shù)據(jù)
        System.out.println("結(jié)束 " + Thread.currentThread());
        queue.offer(cnt.getAndAdd(1));
    }
}

@Test
public void blockQueue() throws InterruptedException {
    LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(2);
    queue.add(cnt.getAndAdd(1));
    queue.add(cnt.getAndAdd(1));


    new Thread(() -> consumer(queue)).start();
    new Thread(() -> consumer(queue)).start();
    new Thread(() -> consumer(queue)).start();
    new Thread(() -> consumer(queue)).start();

    Thread.sleep(10000);
}

1.5 信號(hào)量Semaphore

上面隊(duì)列的實(shí)現(xiàn)方式,可以使用信號(hào)量Semaphore來(lái)完成,通過(guò)設(shè)置信號(hào)量,來(lái)控制并發(fā)數(shù)

private void semConsumer(Semaphore semaphore) {
    try {
        //同步阻塞,嘗試獲取信號(hào)
        semaphore.acquire(1);
        System.out.println("成功拿到信號(hào),執(zhí)行: " + Thread.currentThread());
        Thread.sleep(2000);
        System.out.println("執(zhí)行完畢,釋放信號(hào): " + Thread.currentThread());
        semaphore.release(1);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void semaphore() throws InterruptedException {
    Semaphore semaphore = new Semaphore(2);

    new Thread(() -> semConsumer(semaphore)).start();
    new Thread(() -> semConsumer(semaphore)).start();
    new Thread(() -> semConsumer(semaphore)).start();
    new Thread(() -> semConsumer(semaphore)).start();
    new Thread(() -> semConsumer(semaphore)).start();

    Thread.sleep(20_000);
}

1.6 計(jì)數(shù)器CountDownLatch

計(jì)數(shù),應(yīng)用場(chǎng)景更偏向于多線程的協(xié)同,比如多個(gè)線程執(zhí)行完畢之后,再處理某些事情;不同于上面的并發(fā)數(shù)的控制,它和柵欄一樣,更多的是行為結(jié)果的統(tǒng)一

這種場(chǎng)景下的使用姿勢(shì)一般如下

重點(diǎn):countDownLatch 計(jì)數(shù)為0時(shí)放行

@Test
public void countDown() throws InterruptedException {
    CountDownLatch countDownLatch = new CountDownLatch(2);

    new Thread(() -> {
        try {
            System.out.println("do something in " + Thread.currentThread());
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();
        }
    }).start();

    new Thread(() -> {
        try {
            System.out.println("do something in t2: " + Thread.currentThread());
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();
        }
    }).start();

    countDownLatch.await();
    System.out.printf("結(jié)束");
}

1.7 柵欄 CyclicBarrier

CyclicBarrier的作用與上面的CountDownLatch相似,區(qū)別在于正向計(jì)數(shù)+1, 只有達(dá)到條件才放行; 且支持通過(guò)調(diào)用reset()重置計(jì)數(shù),而CountDownLatch則不行

一個(gè)簡(jiǎn)單的demo

private void cyclicBarrierLogic(CyclicBarrier barrier, long sleep) {
    // 等待達(dá)到條件才放行
    try {
        System.out.println("準(zhǔn)備執(zhí)行: " + Thread.currentThread() + " at: " + LocalDateTime.now());
        Thread.sleep(sleep);
        int index = barrier.await();
        System.out.println("開始執(zhí)行: " + index + " thread: " + Thread.currentThread() + " at: " + LocalDateTime.now());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void testCyclicBarrier() throws InterruptedException {
    // 到達(dá)兩個(gè)工作線程才能繼續(xù)往后面執(zhí)行
    CyclicBarrier barrier = new CyclicBarrier(2);
    // 三秒之后,下面兩個(gè)線程的才會(huì)輸出 開始執(zhí)行
    new Thread(() -> cyclicBarrierLogic(barrier, 1000)).start();
    new Thread(() -> cyclicBarrierLogic(barrier, 3000)).start();

    Thread.sleep(4000);
    // 重置,可以再次使用
    barrier.reset();
    new Thread(() -> cyclicBarrierLogic(barrier, 1)).start();
    new Thread(() -> cyclicBarrierLogic(barrier, 1)).start();
    Thread.sleep(10000);
}

1.8 guava令牌桶

guava封裝了非常簡(jiǎn)單的并發(fā)控制工具類RateLimiter,作為單機(jī)的并發(fā)控制首選

一個(gè)控制qps為2的簡(jiǎn)單demo如下:

private void guavaProcess(RateLimiter rateLimiter) {
    try {
        // 同步阻塞方式獲取
        System.out.println("準(zhǔn)備執(zhí)行: " + Thread.currentThread() + " > " + LocalDateTime.now());
        rateLimiter.acquire();
        System.out.println("執(zhí)行中: " + Thread.currentThread() + " > " + LocalDateTime.now());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void testGuavaRate() throws InterruptedException {
    // 1s 中放行兩個(gè)請(qǐng)求
    RateLimiter rateLimiter = RateLimiter.create(2.0d);
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();
    new Thread(() -> guavaProcess(rateLimiter)).start();

    Thread.sleep(20_000);
}

輸出:

準(zhǔn)備執(zhí)行: Thread[Thread-2,5,main] > 2021-04-13T10:18:05.263
準(zhǔn)備執(zhí)行: Thread[Thread-1,5,main] > 2021-04-13T10:18:05.263
準(zhǔn)備執(zhí)行: Thread[Thread-5,5,main] > 2021-04-13T10:18:05.264
準(zhǔn)備執(zhí)行: Thread[Thread-7,5,main] > 2021-04-13T10:18:05.264
準(zhǔn)備執(zhí)行: Thread[Thread-3,5,main] > 2021-04-13T10:18:05.263
準(zhǔn)備執(zhí)行: Thread[Thread-4,5,main] > 2021-04-13T10:18:05.264
準(zhǔn)備執(zhí)行: Thread[Thread-6,5,main] > 2021-04-13T10:18:05.263
執(zhí)行中: Thread[Thread-2,5,main] > 2021-04-13T10:18:05.267
執(zhí)行中: Thread[Thread-6,5,main] > 2021-04-13T10:18:05.722
執(zhí)行中: Thread[Thread-4,5,main] > 2021-04-13T10:18:06.225
執(zhí)行中: Thread[Thread-3,5,main] > 2021-04-13T10:18:06.721
執(zhí)行中: Thread[Thread-7,5,main] > 2021-04-13T10:18:07.221
執(zhí)行中: Thread[Thread-5,5,main] > 2021-04-13T10:18:07.720
執(zhí)行中: Thread[Thread-1,5,main] > 2021-04-13T10:18:08.219

1.9 滑動(dòng)窗口TimeWindow

沒有找到通用的滑動(dòng)窗口jar包,一般來(lái)講滑動(dòng)窗口更適用于平滑的限流,解決瞬時(shí)高峰問(wèn)題

一個(gè)供參考的實(shí)現(xiàn)方式:

固定大小隊(duì)列,隊(duì)列中每個(gè)數(shù)據(jù)代表一個(gè)時(shí)間段的計(jì)數(shù),

訪問(wèn) -》 隊(duì)列頭拿數(shù)據(jù)(注意不出隊(duì))-》判斷是否跨時(shí)間段 -》 同一時(shí)間段,計(jì)數(shù)+1 -》跨時(shí)間段,新增數(shù)據(jù)入隊(duì),若

扔不進(jìn)去,表示時(shí)間窗滿,隊(duì)尾數(shù)據(jù)出隊(duì)

問(wèn)題:當(dāng)流量稀疏時(shí),導(dǎo)致不會(huì)自動(dòng)釋放過(guò)期的數(shù)據(jù)

解決方案:根據(jù)時(shí)間段設(shè)置定時(shí)任務(wù),模擬訪問(wèn)操作,只是將計(jì)數(shù)改為 + 0

1.10 小結(jié)

本文給出了幾種單機(jī)版的并發(fā)控制的技術(shù)手段,主要目的是介紹了一些可選的方案,技術(shù)細(xì)節(jié)待后續(xù)補(bǔ)全完善,當(dāng)然如果有其他的建議,歡迎評(píng)論交流

到此這篇關(guān)于Java中常見的并發(fā)控制手段的文章就介紹到這了,更多相關(guān)Java并發(fā)控制手段內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot3.0集成MybatisPlus的實(shí)現(xiàn)方法

    SpringBoot3.0集成MybatisPlus的實(shí)現(xiàn)方法

    本文主要介紹了SpringBoot3.0集成MybatisPlus的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • 詳解Spring與Mybatis整合方法(基于IDEA中的Maven整合)

    詳解Spring與Mybatis整合方法(基于IDEA中的Maven整合)

    這篇文章主要介紹了Spring與Mybatis整合方法(基于IDEA中的Maven整合),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 淺談Java內(nèi)部類——靜態(tài)內(nèi)部類

    淺談Java內(nèi)部類——靜態(tài)內(nèi)部類

    這篇文章主要介紹了Java靜態(tài)內(nèi)部類的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java內(nèi)部類的相關(guān)知識(shí),感興趣的朋友可以了解下
    2020-08-08
  • Spring Boot部署到Tomcat過(guò)程中遇到的問(wèn)題匯總

    Spring Boot部署到Tomcat過(guò)程中遇到的問(wèn)題匯總

    這篇文章主要給大家分享了關(guān)于Spring Boot部署到Tomcat過(guò)程中遇到的一些問(wèn)題,文中將解決的方法介紹非常詳細(xì),對(duì)同樣遇到這個(gè)問(wèn)題的朋友具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • 在idea中設(shè)置項(xiàng)目編碼格式為UTF-8的操作方法

    在idea中設(shè)置項(xiàng)目編碼格式為UTF-8的操作方法

    idea中的默認(rèn)編碼為GBK,在開發(fā)過(guò)程中一般將編碼格式改為UTF-8,所以本文給大家介紹了在idea中設(shè)置項(xiàng)目編碼為UTF-8的操作方法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Java把list分成多個(gè)list的方法示例

    Java把list分成多個(gè)list的方法示例

    在編程中將大的list集合拆分為多個(gè)小集合可以提高處理效率,主要拆分方法包括等量拆分適用于均勻處理數(shù)據(jù)、?指定數(shù)量拆分按固定子集大小劃分、根據(jù)條件拆分按特定規(guī)則進(jìn)行,這些方法有助于多線程異步處理,需要的朋友可以參考下
    2024-11-11
  • 14個(gè)編寫Spring MVC控制器的實(shí)用小技巧(吐血整理)

    14個(gè)編寫Spring MVC控制器的實(shí)用小技巧(吐血整理)

    這篇文章主要介紹了14個(gè)編寫Spring MVC控制器的實(shí)用小技巧(吐血整理),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng)

    java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • TF-IDF理解及其Java實(shí)現(xiàn)代碼實(shí)例

    TF-IDF理解及其Java實(shí)現(xiàn)代碼實(shí)例

    這篇文章主要介紹了TF-IDF理解及其Java實(shí)現(xiàn)代碼實(shí)例,簡(jiǎn)單介紹了tfidf算法及其相應(yīng)公式,然后分享了Java實(shí)現(xiàn)代碼,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Java開發(fā)學(xué)習(xí)之Bean的作用域和生命周期詳解

    Java開發(fā)學(xué)習(xí)之Bean的作用域和生命周期詳解

    這篇文章主要介紹了淺談Spring中Bean的作用域,生命周期和注解,從創(chuàng)建到消亡的完整過(guò)程,例如人從出生到死亡的整個(gè)過(guò)程就是一個(gè)生命周期。本文將通過(guò)示例為大家詳細(xì)講講,感興趣的可以學(xué)習(xí)一下
    2022-06-06

最新評(píng)論

陕西省| 当阳市| 东乡族自治县| 丹巴县| 日照市| 浦东新区| 布尔津县| 安阳市| 旬阳县| 河东区| 永新县| 黄大仙区| 平定县| 葫芦岛市| 太湖县| 化州市| 得荣县| 郯城县| 张家港市| 阜宁县| 富锦市| 固安县| 高邑县| 焉耆| 嘉祥县| 临邑县| 唐山市| 腾冲县| 巴彦县| 左云县| 连平县| 东乌珠穆沁旗| 龙井市| 阿荣旗| 株洲市| 五原县| 邹城市| 天津市| 黔江区| 威宁| 浮梁县|