<del id="nnjnj"></del><track id="nnjnj"></track>

<p id="nnjnj"></p>

<address id="nnjnj"></address>

    <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

      <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>

      • 自動秒收錄
      • 軟件:1973
      • 資訊:56179|
      • 收錄網站:177773|

      IT精英團

      SpringBoot開發案例之多任務并行+線程池處理

      SpringBoot開發案例之多任務并行+線程池處理

      瀏覽次數:
      評論次數:
      編輯: 小柒2015
      信息來源: 51CTO博客
      更新日期: 2020-10-29 15:07:51
      摘要

      前言前幾篇文章著重介紹了后端服務數據庫和多線程并行處理優化,并示例了改造前后的偽代碼邏輯。當然了,優化是無止境的,前人栽樹后人乘涼。作為我們開發者來說,既然站在了巨人的肩膀上,就要寫出更加優化的程序。SpringBoot開發案例之JdbcTemplate批量操作SpringBoot開發案例之CountDownLatch多任務并行處理改造理論上講,線程越多程序可能更快,但是在實際使用中我們需要考慮到

      • 正文開始
      • 相關閱讀
      • 推薦作品

      前言

      前幾篇文章著重介紹了后端服務數據庫和多線程并行處理優化,并示例了改造前后的偽代碼邏輯。當然了,優化是無止境的,前人栽樹后人乘涼。作為我們開發者來說,既然站在了巨人的肩膀上,就要寫出更加優化的程序。

      • SpringBoot開發案例之JdbcTemplate批量操作

      • SpringBoot開發案例之CountDownLatch多任務并行處理

      改造

      理論上講,線程越多程序可能更快,但是在實際使用中我們需要考慮到線程本身的創建以及銷毀的資源消耗,以及保護操作系統本身的目的。我們通常需要將線程限制在一定的范圍之類,線程池就起到了這樣的作用。

      程序邏輯

      一張圖能解決的問題,就應該盡可能的少BB,當然底層原理性的東西還是需要大家去記憶并理解的。

      Java 線程池

      Java通過Executors提供四種線程池,分別為:

      • newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。

      • newFixedThreadPool 創建一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。

      • newScheduledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。

      • newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

      優點

      • 重用存在的線程,減少對象創建、消亡的開銷,性能佳。

      • 可有效控制最大并發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。

      • 提供定時執行、定期執行、單線程、并發數控制等功能。

      代碼實現

      方式一(CountDownLatch)
      /**
      ?*?多任務并行+線程池統計
      ?*?創建者?科幫網??https://blog.52itstyle.com
      ?*?創建時間????2018年4月17日
      ?*/public?class?StatsDemo?{????final?static?SimpleDateFormat?sdf?=?new?SimpleDateFormat(????????????"yyyy-MM-dd?HH:mm:ss");????
      ????final?static?String?startTime?=?sdf.format(new?Date());????
      ????/**
      	?*?IO密集型任務??=?一般為2*CPU核心數(常出現于線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)
      	?*?CPU密集型任務?=?一般為CPU核心數+1(常出現于線程中:復雜算法)
      	?*?混合型任務??=?視機器配置和復雜度自測而定
      	?*/
      	private?static?int?corePoolSize?=?Runtime.getRuntime().availableProcessors();	/**
      	?*?public?ThreadPoolExecutor(int?corePoolSize,int?maximumPoolSize,long?keepAliveTime,
      	?*???????????????????????????TimeUnit?unit,BlockingQueue<Runnable>?workQueue)
      	?*?corePoolSize用于指定核心線程數量
      	?*?maximumPoolSize指定最大線程數
      	?*?keepAliveTime和TimeUnit指定線程空閑后的最大存活時間
      	?*?workQueue則是線程池的緩沖隊列,還未執行的線程會在隊列中等待
      	?*?監控隊列長度,確保隊列有界
      	?*?不當的線程池大小會使得處理速度變慢,穩定性下降,并且導致內存泄露。如果配置的線程過少,則隊列會持續變大,消耗過多內存。
      	?*?而過多的線程又會?由于頻繁的上下文切換導致整個系統的速度變緩——殊途而同歸。隊列的長度至關重要,它必須得是有界的,這樣如果線程池不堪重負了它可以暫時拒絕掉新的請求。
      	?*?ExecutorService?默認的實現是一個***的?LinkedBlockingQueue。
      	?*/
      	private?static?ThreadPoolExecutor?executor??=?new?ThreadPoolExecutor(corePoolSize,?corePoolSize+1,?10l,?TimeUnit.SECONDS,			new?LinkedBlockingQueue<Runnable>(1000));	
      ????public?static?void?main(String[]?args)?throws?InterruptedException?{
      ????????CountDownLatch?latch?=?new?CountDownLatch(5);????????//使用execute方法
      ??		executor.execute(new?Stats("任務A",?1000,?latch));
      ??		executor.execute(new?Stats("任務B",?1000,?latch));
      ??		executor.execute(new?Stats("任務C",?1000,?latch));
      ??		executor.execute(new?Stats("任務D",?1000,?latch));
      ??		executor.execute(new?Stats("任務E",?1000,?latch));
      ????????latch.await();//?等待所有人任務結束
      ????????System.out.println("所有的統計任務執行完成:"?+?sdf.format(new?Date()));
      ????}????static?class?Stats?implements?Runnable??{
      ????????String?statsName;????????int?runTime;
      ????????CountDownLatch?latch;????????public?Stats(String?statsName,?int?runTime,?CountDownLatch?latch)?{????????????this.statsName?=?statsName;????????????this.runTime?=?runTime;????????????this.latch?=?latch;
      ????????}????????public?void?run()?{????????????try?{
      ????????????????System.out.println(statsName+?"?do?stats?begin?at?"+?startTime);????????????????//模擬任務執行時間
      ????????????????Thread.sleep(runTime);
      ????????????????System.out.println(statsName?+?"?do?stats?complete?at?"+?sdf.format(new?Date()));
      ????????????????latch.countDown();//單次任務結束,計數器減一
      ????????????}?catch?(InterruptedException?e)?{
      ????????????????e.printStackTrace();
      ????????????}
      ????????}
      ????}
      }
      方式二(Future)
      /**
      ?*?多任務并行+線程池統計
      ?*?創建者?科幫網?https://blog.52itstyle.com
      ?*?創建時間????2018年4月17日
      ?*/public?class?StatsDemo?{????final?static?SimpleDateFormat?sdf?=?new?SimpleDateFormat(????????????"yyyy-MM-dd?HH:mm:ss");????
      ????final?static?String?startTime?=?sdf.format(new?Date());????
      ????/**
      	?*?IO密集型任務??=?一般為2*CPU核心數(常出現于線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)
      	?*?CPU密集型任務?=?一般為CPU核心數+1(常出現于線程中:復雜算法)
      	?*?混合型任務??=?視機器配置和復雜度自測而定
      	?*/
      	private?static?int?corePoolSize?=?Runtime.getRuntime().availableProcessors();	/**
      	?*?public?ThreadPoolExecutor(int?corePoolSize,int?maximumPoolSize,long?keepAliveTime,
      	?*???????????????????????????TimeUnit?unit,BlockingQueue<Runnable>?workQueue)
      	?*?corePoolSize用于指定核心線程數量
      	?*?maximumPoolSize指定最大線程數
      	?*?keepAliveTime和TimeUnit指定線程空閑后的最大存活時間
      	?*?workQueue則是線程池的緩沖隊列,還未執行的線程會在隊列中等待
      	?*?監控隊列長度,確保隊列有界
      	?*?不當的線程池大小會使得處理速度變慢,穩定性下降,并且導致內存泄露。如果配置的線程過少,則隊列會持續變大,消耗過多內存。
      	?*?而過多的線程又會?由于頻繁的上下文切換導致整個系統的速度變緩——殊途而同歸。隊列的長度至關重要,它必須得是有界的,這樣如果線程池不堪重負了它可以暫時拒絕掉新的請求。
      	?*?ExecutorService?默認的實現是一個***的?LinkedBlockingQueue。
      	?*/
      	private?static?ThreadPoolExecutor?executor??=?new?ThreadPoolExecutor(corePoolSize,?corePoolSize+1,?10l,?TimeUnit.SECONDS,			new?LinkedBlockingQueue<Runnable>(1000));	
      ????public?static?void?main(String[]?args)?throws?InterruptedException?{
      ????	List<Future<String>>?resultList?=?new?ArrayList<Future<String>>();?
      ????????//使用submit提交異步任務,并且獲取返回值為future
      ????	resultList.add(executor.submit(new?Stats("任務A",?1000)));
      ????	resultList.add(executor.submit(new?Stats("任務B",?1000)));
      ????	resultList.add(executor.submit(new?Stats("任務C",?1000)));
      ????	resultList.add(executor.submit(new?Stats("任務D",?1000)));
      ????	resultList.add(executor.submit(new?Stats("任務E",?1000)));??	???//遍歷任務的結果
      ????????for?(Future<String>?fs?:?resultList)?{?
      ????????????try?{?
      ????????????????System.out.println(fs.get());//打印各個線任務執行的結果,調用future.get()?阻塞主線程,獲取異步任務的返回結果
      ????????????}?catch?(InterruptedException?e)?{?
      ????????????????e.printStackTrace();?
      ????????????}?catch?(ExecutionException?e)?{?
      ????????????????e.printStackTrace();?
      ????????????}?finally?{?
      ????????????????//啟動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
      ????????????	executor.shutdown();?
      ????????????}?
      ????????}?
      ????????System.out.println("所有的統計任務執行完成:"?+?sdf.format(new?Date()));
      ????}????static?class?Stats?implements?Callable<String>??{
      ????????String?statsName;????????int?runTime;????????public?Stats(String?statsName,?int?runTime)?{????????????this.statsName?=?statsName;????????????this.runTime?=?runTime;
      ????????}????????public?String?call()?{????????????try?{
      ????????????????System.out.println(statsName+?"?do?stats?begin?at?"+?startTime);????????????????//模擬任務執行時間
      ????????????????Thread.sleep(runTime);
      ????????????????System.out.println(statsName?+?"?do?stats?complete?at?"+?sdf.format(new?Date()));
      ????????????}?catch?(InterruptedException?e)?{
      ????????????????e.printStackTrace();
      ????????????}????????????return?call();
      ????????}
      ????}
      }

      執行時間

      以上代碼,均是偽代碼,下面是2000+個學生的真實測試記錄。

      2018-04-17?17:42:29.284?INFO???測試記錄81e51ab031eb4ada92743ddf66528d82-單線程順序執行,花費時間:37972018-04-17?17:42:31.452?INFO???測試記錄81e51ab031eb4ada92743ddf66528d82-多線程并行任務,花費時間:21672018-04-17?17:42:33.170?INFO???測試記錄81e51ab031eb4ada92743ddf66528d82-多線程并行任務+線程池,花費時間:1717


      聊聊Servlet、Struts1、Struts2以及SpringMvc中的線程安全
      ? 上一篇 2020-10-29
      Java中線程池,你真的會用嗎?
      下一篇 ? 2020-10-29
      • 談如何設計未來的倉庫建筑
        4閱讀 0條評論 個贊
        編輯:數據社全文共3758個字,建議10分鐘閱讀大家好,我是峰哥,夏天已經來了,小麥馬上要豐收了,今天分析一篇關于未來數倉架構發展方向的文章。Linked大佬JayKreps曾發表過一篇博客,簡單闡……
      • 高并發服務的幾點優化經驗
        0閱讀 0條評論 個贊
        前言:如何優化高并發服務,這里指的是qps在20萬以上的在線服務,注意不是離線服務,在線服務會存在哪些挑戰呢?①無法做離線緩存,所有的數據都是實時讀的②大量的請求會打到線上服務,對于服務的響應時間要……
      • Java處理異常的9個最佳實踐 你做得對嗎?
        1閱讀 0條評論 個贊
        原文:https://dzone.com/articles/9-best-practices-to-handle-exceptions-in-java譯者:颯然Hang譯文:http://www.r……
      • 提高Java字符串編碼和解碼性能的技巧
        1閱讀 0條評論 個贊
        1常見字符串編碼●常見的字符串編碼有:LATIN1只能保存ASCII字符,又稱ISO-8859-1。UTF-8變長字節編碼,一個字符需要使用1個、2個或者3個byte表示。由于中文通常需要3個字節……
      • Linux預定任務調度(crontab) 好實用!
        0閱讀 0條評論 個贊
        概述crontab命令用于設置周期性被執行的指令。該命令從標準輸入設備讀取指令,并將其存放于“crontab”文件中,以供之后讀取和執行??梢允褂胏rontab定時處理離線任務,比如每天凌晨2點更新數……
      發表評論 共有條評論
      用戶名: 密碼:
      驗證碼: 匿名發表
      • 碼頭工人搭建彈性搜索集群教程
        0閱讀 0條評論 個贊
        寫在前面:為什么要用ElasticSearch?我們的應用經常需要添加檢索功能,開源的ElasticSearch是目前全文檢索引擎的首選。它可以快速的存儲、搜索和分析海量數據。ElasticSear……
      • 如何執行超過100M的SQL腳本?
        2閱讀 0條評論 個贊
        技術_菜鳥https://www.cnblogs.com/hai-ping/p/3939150.html最近遇到一個問題,在SQLServer的查詢分析器里面執行一個超過100MB的數據庫腳本,發現……
      • 如何正確計算Kubernetes容器的CPU利用率
        1閱讀 0條評論 個贊
        本文轉自博客園,原文:https://www.cnblogs.com/apink/p/15767687.html,版權歸原作者所有。參數解釋使用Prometheus配置kubernetes環境……
      • Linux的10個最危險的命令
        0閱讀 0條評論 個贊
        rm-rf命令該命令可能導致不可恢復的系統崩壞。>rm-rf/#強制刪除根目錄下所有東西。>rm-rf*#強制刪除當前目錄的所有文件。>rm-rf.#強制刪除當前文件夾及其子文件夾。執行rm-r……
      • 一天一技能:協調與多流程的完美結合
        7閱讀 0條評論 個贊
        我們知道,協程本質上是單線程單進程,通過充分利用IO等待時間來實現高并發。在IO等待時間之外的代碼,還是串行運行的。因此,如果協程非常多,多少每個協程內部的串行代碼運行時間超過了IO請求的等待時間,那……
      • MySQL批量插入數據 一次插入多少行數據效率最高?
        7閱讀 0條評論 個贊
        一、前言我們在操作大型數據表或者日志文件的時候經常會需要寫入數據到數據庫,那么最合適的方案就是數據庫的批量插入。只是我們在執行批量操作的時候,一次插入多少數據才合適呢?假如需要插入的數據有百萬條,那……
      • SQL中的三種重復數據刪除方法 還有誰不行?
        0閱讀 0條評論 個贊
        SQL去重是數據分析工作中比較常見的一個場景,今天給大家具體介紹3種去重的方法。在使用SQL提數的時候,常會遇到表內有重復值的時候,比如我們想得到uv(獨立訪客),就需要做去重。在MySQL中……
      • 在Linux中檢查磁盤空間的12個有用的df命令
        1閱讀 0條評論 個贊
        1.檢查文件系統磁盤空間使用情況這df命令顯示文件系統上的設備名稱、總塊數、總磁盤空間、已用磁盤空間、可用磁盤空間和掛載點信息。[root@local~]#dfFilesystem1K-bloc……
      • 如何優雅地升級Kubernetes集群的Docker和Containerd版本
        1閱讀 0條評論 個贊
        前言公司用的k8s集群是“多環境合一”的方式,集群流量入口也摒棄了常見的traefik和ingress-nginx,直接用了一個國內不常見的底層基于Envoy的APIGateway網關服務。當然還有……
      • 基礎鞏固——至少需要多少行代碼才能實現深度復制?
        1閱讀 0條評論 個贊
        前言深度克?。ㄉ羁截悾┮恢倍际浅?、中級前端面試中經常被問到的題目,網上介紹的實現方式也都各有千秋,大體可以概括為三種方式:JSON.stringify+JSON.parse,這個很好理解;全量判斷類……
      • 一行Python代碼實現程序并行
        1閱讀 0條評論 個贊
        Python在程序并行化方面多少有些聲名狼藉。撇開技術上的問題,例如線程的實現和GIL,我覺得錯誤的教學指導才是主要問題。常見的經典Python多線程、多進程教程多顯得偏"重"。而且往往隔靴搔……
      • 誤操作離線丟棄和恢復場景測試的業務影響——來自“血”的教訓
        0閱讀 0條評論 個贊
        在數據庫恢復過程中,比如我們用了第三方的備份工具,在實施恢復操作時會導出需要的某個表空間這樣可以大大減少恢復時間,是十分值得推薦的做法,這個過程中由于修改控制文件中數據文件的相關信息,需要執行alte……
      • 數據倉庫實踐:總線矩陣體系結構的設計
        1閱讀 0條評論 個贊
        以下文章來源于公眾號-云祁的數據江湖,作者云祁如何設計一套切實可行的數據倉庫呢?我們要明白,對于數據倉庫的設計是不能完全依賴于業務的需求,但往往又必須要服務于業務的價值。因此,在構建數據倉庫前,我們……
      • MYSQL VS POLARDB唯一索引死鎖及應用設計
        1閱讀 0條評論 個贊
        #issue68021MySQLuniquecheck問題-知乎(zhihu.com)事情的開始是這樣的,最近和阿里云密切聯系,也成為他們的大客戶,(我們當然是大客戶,BIGBIG……
      • 做SQL性能優化真的是干瞪眼
        1閱讀 0條評論 個贊
        很多大數據計算都是用SQL實現的,跑得慢時就要去優化SQL,但常常碰到讓人干瞪眼的情況。比如,存儲過程中有三條大概形如這樣的語句執行得很慢:selecta,b,sum(x)fromTgr……
      • 談如何設計未來的倉庫建筑
        4閱讀 0條評論 個贊
        編輯:數據社全文共3758個字,建議10分鐘閱讀大家好,我是峰哥,夏天已經來了,小麥馬上要豐收了,今天分析一篇關于未來數倉架構發展方向的文章。Linked大佬JayKreps曾發表過一篇博客,簡單闡……
      • 采訪者:告訴我們SpringAOP的底層代理模型
        2閱讀 0條評論 個贊
        來源|Java技術指北(ID:javanorth)代理模式相信大家經常聽說,在設計模式中相對而言是比較難理解的。這次指北君來給大家通俗的介紹介紹。1、什么是代理模式Provideasurrog……
      • 7 種提升Spring Boot吞吐量神技!
        0閱讀 0條評論 個贊
        一、異步執行實現方式二種:1.使用異步注解@aysnc、啟動類:添加@EnableAsync注解2.JDK8本身有一個非常好用的Future類——CompletableFuture@AllArg……
      • 管理數百個Kubernetes集群需要什么?
        0閱讀 0條評論 個贊
        文章轉載:進擊云原生(版權歸原作者所有,侵刪)要點:部署一個具備生產就緒所需所有依賴關系的Kubernetes集群需要數天時間。如果不自動化這個過程,管理Kubernetes集群的浮動是非常困難的。在……
      • JD.COM面試問題:ElasticSearch深度分頁解決方案
        0閱讀 0條評論 個贊
        以下文章來源于月伴飛魚,作者日常加油站前言Elasticsearch是一個實時的分布式搜索與分析引擎,在使用過程中,有一些典型的使用場景,比如分頁、遍歷等。在使用關系型數據庫中,我們被告知要注意甚至……
      最近發布資訊
      更多
      警花高潮嗷嗷叫
      <del id="nnjnj"></del><track id="nnjnj"></track>

      <p id="nnjnj"></p>

      <address id="nnjnj"></address>

        <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

          <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>