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

java如何多線程批量更新10萬級的數(shù)據(jù)

 更新時間:2024年10月12日 08:42:30   作者:carter171717  
在處理大數(shù)據(jù)量的批量更新時,直接使用mybatis的updateBatch可能導致效率低下甚至OOM,通過每次處理5000條數(shù)據(jù)的方式雖然安全但效率低,更優(yōu)的解決方案是使用多線程處理,將數(shù)據(jù)分批并多線程執(zhí)行,有效提高了處理速度并保證了系統(tǒng)穩(wěn)定性

java多線程批量更新10萬級的數(shù)據(jù)

好久沒有寫文章,今天剛好沒啥事,就動手記錄一下,好記性不如爛筆頭!言歸正傳,我最近接到的一個工作任務大概內(nèi)容是,有一張數(shù)據(jù)量在十萬+級別的表,需要新增一個字段,并且要寫入初始化值。

業(yè)務其實非常的簡單,全部查詢出來一個列表,然后用mybatis的updateBatch批量更新,其實在我的實踐過程中也沒什么問題,但是執(zhí)行的效率是很低的,而且一旦數(shù)據(jù)量過大,如果機器配置不太行的話,很可能會直接OOM,如果在正式環(huán)境出現(xiàn)這個問題,那完犢子,準備刪庫跑路!

所以呢,我就想了一個比較保險但是比較低級的辦法,每次查詢出5000條數(shù)據(jù),去做批量更新,確保內(nèi)存不會溢出導致服務崩盤,這當然也是可以解決問題,但是就是修復數(shù)據(jù)需要執(zhí)行很多次,顯得比較愚蠢一點。

如何用比較方便并高效的方式來修復大數(shù)量的數(shù)據(jù)

第一反應肯定是多線程啦,方案是:

  • 1.查詢出全部的數(shù)據(jù)(10萬條)
  • 2.對數(shù)據(jù)進行分批,每批5000條,
  • 3.多線程同時處理多批數(shù)據(jù)
  • 4.等待執(zhí)行完成,返回成功

直接上核心代碼

寫一個通用的分批工具類,把一個List集合,拆分成多個小的List集合

/**
 * 拆分集合
 *
 * @param <T> 泛型對象
 * @param resList 需要拆分的集合
 * @param subListLength 每個子集合的元素個數(shù)
 * @return 返回拆分后的各個集合組成的列表
 **/
public static <T> List<List<T>> splitList(List<T> resList, int subListLength) {
    if (CollectionUtils.isEmpty(resList) || subListLength <= 0) {
        return new ArrayList<>();
    }
    List<List<T>> ret = new ArrayList<>();
    int size = resList.size();
    if (size <= subListLength) {
        // 數(shù)據(jù)量不足 subListLength 指定的大小
        ret.add(resList);
    } else {
        int pre = size / subListLength;
        int last = size % subListLength;
        // 前面pre個集合,每個大小都是 subListLength 個元素
        for (int i = 0; i < pre; i++) {
            List<T> itemList = new ArrayList<>(subListLength);
            for (int j = 0; j < subListLength; j++) {
                itemList.add(resList.get(i * subListLength + j));
            }
            ret.add(itemList);
        }

        // last的進行處理
        if (last > 0) {
            List<T> itemList = new ArrayList<>(last);
            for (int i = 0; i < last; i++) {
                itemList.add(resList.get(pre * subListLength + i));
            }
            ret.add(itemList);
        }
    }
    return ret;
}

然后就是用多線程業(yè)務處理了,代碼如下

 public static void doThreadBusiness(List<String> totalList) {
        Long startTime = System.currentTimeMillis();
        System.out.println("本次更新任務開始");
        System.out.println("本機CPU核心數(shù):"+Runtime.getRuntime().availableProcessors());
        List<String> updateList = new ArrayList();
        // 初始化線程池, 參數(shù)一定要一定要一定要調(diào)好?。。?!
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 50,
                4, TimeUnit.SECONDS, new ArrayBlockingQueue(10), new ThreadPoolExecutor.DiscardPolicy());
        // 大集合拆分成N個小集合,然后用多線程去處理數(shù)據(jù),確保不會因為數(shù)據(jù)量過大導致執(zhí)行過慢
        List<List<String>> splitNList = SplitListUtils.splitList(totalList, 5000);
        // 記錄單個任務的執(zhí)行次數(shù)
        CountDownLatch countDownLatch = new CountDownLatch(splitNList.size());
        // 對拆分的集合進行批量處理, 先拆分的集合, 再多線程執(zhí)行
        for (List<String> singleList : splitNList) {
            // 線程池執(zhí)行
            threadPool.execute(new Thread(new Runnable(){
                @Override
                public void run() {
                    //模擬執(zhí)行時間
                    System.out.println("當前線程:"+Thread.currentThread().getName());
                    List<String> batchUpdateVipList = new ArrayList<>();
                    for (String str : singleList) {
                        //組裝要執(zhí)行的批量更新數(shù)據(jù)
                        batchUpdateVipList.add(str);
                    }
                    // 這里模擬執(zhí)行數(shù)據(jù)庫批量更新操作
                    System.out.println("本次批量更新數(shù)據(jù)量:"+ batchUpdateVipList.size());
                    // 任務個數(shù) - 1, 直至為0時喚醒await()
                    countDownLatch.countDown();
                }
            }));
        }
        try {
            // 讓當前線程處于阻塞狀態(tài),直到鎖存器計數(shù)為零
            countDownLatch.await();
        } catch (Exception e) {
            System.out.println("系統(tǒng)出現(xiàn)異常");
        }
        Long endTime = System.currentTimeMillis();
        Long useTime = endTime - startTime;
        System.out.println("本次更新任務結(jié)束,共計用時"+useTime+"毫秒");
    }

代碼很 簡單一看就懂了,這里要說一下CountDownLatch的使用,其實開發(fā)中并不常用,但是面試卻很常用,這里蠻寫一下,我使用CountDownLatch來阻塞主線程,等待多線程執(zhí)行完畢后,再繼續(xù)主線程,返回更新的結(jié)果,這個場景其實很經(jīng)常使用到。

如果不用CountDownLatch,主線程會馬上返回,如果是數(shù)據(jù)量大的情況下,往往會執(zhí)行蠻久的,但是結(jié)果秒返回,就會給人一種錯覺。

CountDownLatch countDownLatch = new CountDownLatch(splitNList.size());

在線程執(zhí)行完畢后,需要調(diào)用一下countDown,

// 任務個數(shù) - 1, 直至為0時喚醒await()
countDownLatch.countDown();

在主線程用await()進行阻塞等待,這樣主線程就會一直等到所有的子線程都執(zhí)行完成了,繼續(xù)執(zhí)行主線程的后續(xù)代碼

 countDownLatch.await();

其實這里面還有一個非常重要的面試點,就是多線程的七大參數(shù)如何設置,

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 
50,
4, 
TimeUnit.SECONDS, 
new ArrayBlockingQueue(10), 
new ThreadPoolExecutor.DiscardPolicy()
);

有興趣了解具體是設置方法可以另行查詢資料,這也是面試必問的考點。

最后貼一下返回的打印結(jié)果吧,如下圖所示:

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于application.yml數(shù)據(jù)庫配置方式

    關(guān)于application.yml數(shù)據(jù)庫配置方式

    這篇文章主要介紹了關(guān)于application.yml數(shù)據(jù)庫配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 關(guān)于TransmittableThreadLocal線程池中線程復用問題的解決方案

    關(guān)于TransmittableThreadLocal線程池中線程復用問題的解決方案

    這篇文章主要介紹了關(guān)于TransmittableThreadLocal線程池中線程復用問題的解決方案,線程池復用線程,如果子線程執(zhí)行完未移除上下文,則會導致后續(xù)線程可以取到之前線程設置的屬性,需要的朋友可以參考下
    2023-11-11
  • java.net.SocketException: Connection reset 解決方法

    java.net.SocketException: Connection reset 解決方法

    最近糾結(jié)致死的一個java報錯java.net.SocketException: Connection reset 終于得到解決
    2013-03-03
  • Java中String類詳解之字符串操作的必備知識

    Java中String類詳解之字符串操作的必備知識

    Java String類是Java編程語言中的核心類,用于高效處理字符串操作,它在面試中常被問到,因為理解其特性與用法對于編寫高質(zhì)量的代碼至關(guān)重要,這篇文章主要介紹了Java中String類詳解之字符串操作的必備知識,需要的朋友可以參考下
    2025-09-09
  • java springboot郵箱找回密碼功能的實現(xiàn)講解

    java springboot郵箱找回密碼功能的實現(xiàn)講解

    這篇文章主要介紹了java springboot郵箱找回密碼功能的實現(xiàn)講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • IDEA中Maven Dependencies出現(xiàn)紅色波浪線的原因及解決方法

    IDEA中Maven Dependencies出現(xiàn)紅色波浪線的原因及解決方法

    在使用 IntelliJ IDEA 開發(fā) Java 項目時,尤其是基于 Maven 的項目,您可能會遇到 Maven Dependencies 中出現(xiàn)紅色波浪線的問題,這通常意味著項目的依賴無法被正確解析或下載,本文將詳細介紹該問題的原因及解決方法,并附有圖文說明,需要的朋友可以參考下
    2025-06-06
  • SpringBoot中的ImportSelector類動態(tài)加載bean詳解

    SpringBoot中的ImportSelector類動態(tài)加載bean詳解

    這篇文章主要介紹了SpringBoot中的ImportSelector類動態(tài)加載bean詳解,ImportSelector接口是spring中導入外部配置的核心接口,根據(jù)給定的條件(通常是一個或多個注釋屬性)判定要導入那個配置類,在spring自動化配置和@EnableXXX中都有它的存在,需要的朋友可以參考下
    2024-01-01
  • JAVA根據(jù)ip地址獲取歸屬地的實現(xiàn)方法

    JAVA根據(jù)ip地址獲取歸屬地的實現(xiàn)方法

    本文主要介紹了JAVA根據(jù)ip地址獲取歸屬地的實現(xiàn)方法,要通過Java程序獲取IP地址對應的城市,需要借助第三方的IP地址庫,下面就來介紹一下,感興趣的可以了解一下
    2023-10-10
  • SpringBoot集成 Prometheus進行高效監(jiān)控的實現(xiàn)

    SpringBoot集成 Prometheus進行高效監(jiān)控的實現(xiàn)

    Prometheus作為一個開源的監(jiān)控和告警工具,以其強大的數(shù)據(jù)采集、存儲和查詢能力,受到了眾多開發(fā)者的青睞,本文主要介紹了SpringBoot集成 Prometheus進行高效監(jiān)控的實現(xiàn),感興趣的可以了解一下
    2024-07-07
  • Java Swing實現(xiàn)餐廳點餐系統(tǒng)源碼(收藏版)

    Java Swing實現(xiàn)餐廳點餐系統(tǒng)源碼(收藏版)

    這篇文章主要介紹了Java Swing實現(xiàn)餐廳點餐系統(tǒng)源碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02

最新評論

南皮县| 沈丘县| 大石桥市| 平遥县| 胶南市| 临沂市| 依安县| 厦门市| 平度市| 辉南县| 乐清市| 安仁县| 广西| 津南区| 长乐市| 佛坪县| 武隆县| 麟游县| 娄烦县| 西林县| 来安县| 塔河县| 稻城县| 城市| 浙江省| 沧源| 兴安盟| 尼玛县| 青川县| 双辽市| 湘西| 遂溪县| 罗平县| 科尔| 麻江县| 永兴县| 蓬莱市| 金溪县| 固镇县| 云和县| 肥乡县|