SpringBoot(一) 多線程與非同步

来源:https://www.cnblogs.com/lyldelove/archive/2020/07/09/13270351.html
-Advertisement-
Play Games

多線程與非同步 非同步是目的,而多線程是實現這個目的的方法。 1 Java J.U.C線程調度 JDK 1.5新增的java.util.concurrent包,增加了併發編程的很多類。 Executor 定義了方法execute(),用來執行一個任務 public interface Executor ...


多線程與非同步

非同步是目的,而多線程是實現這個目的的方法。

1 Java J.U.C線程調度

JDK 1.5新增的java.util.concurrent包,增加了併發編程的很多類。

image-20200707230102829

Executor

定義了方法execute(),用來執行一個任務

public interface Executor {
    void execute(Runnable command);
}
ExecutorService

提供了生命周期管理的方法。

submit()

shutdown()

invokeAll()

invokeAny()

ThreadPoolExecutor

Java提供的線程池類。可自定義線程池大小及線程處理機制。

corePoolSize:線程池的基本大小,即在沒有任務需要執行的時候線程池的大小,並且只有在工作隊列滿了的情況下才會創建超出這個數量的線程。

maximumPoolSize:線程池中允許的最大線程數,線程池中的當前線程數目不會超過該值。

keepAliveTime:線程空閑時間

poolSize表示當前線程數,新提交一個任務時的處理流程為:

  • 如果當前線程池的線程數還沒有達到基本大小(poolSize < corePoolSize),無論是否有空閑的線程新增一個線程處理新提交的任務

  • 如果當前線程池的線程數大於或等於基本大小(poolSize >= corePoolSize) 且任務隊列未滿時,就將新提交的任務提交到阻塞隊列排隊,等候處理。

  • 如果當前線程池的線程數大於或等於基本大小(poolSize >= corePoolSize) 且任務隊列滿時:

    • 當前poolSize<maximumPoolSize,那麼就新增線程來處理任務
    • 當前poolSize=maximumPoolSize,那麼意味著線程池的處理能力已經達到了極限,此時需要拒絕新增加的任務。至於如何拒絕處理新增的任務,取決於線程池的飽和策略RejectedExecutionHandler。
ScheduledExecutorService

定時調度介面。有4種調度機制:

//帶延遲時間的調度,只執行一次,調度之後可通過Future.get()阻塞直至任務執行完畢
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
//帶延遲時間的調度,只執行一次,調度之後可通過Future.get()阻塞直至任務執行完畢,並且可以獲取執行結果
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
//帶延遲時間的調度,迴圈執行,固定頻率
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
//帶延遲時間的調度,迴圈執行,固定延遲
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
ScheduledThreadPoolExecutor

基於線程池的定時調度實現。可以用來在給定延時後執行非同步任務或者周期性執行任務。

ScheduledExecutorService4種調度機制的實現。

2 Spring線程調度

image-20200707232349760

TaskExecutor

Spring引入了TaskExecutor介面作為頂層介面。繼承至J.U.C的Executor介面。

TaskScheduler

類似於J.U.C中的ScheduledExecutorService,是任務調度的介面。

功能與ScheduledExecutorService差不多,多了一個可傳Trigger對象的schedule()方法,可支持Corn表達式進行任務調度。

ScheduledFuture<?> schedule(Runnable task, Trigger trigger);
ScheduledFuture<?> schedule(Runnable task, Date startTime);
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period);
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay);
AsyncTaskExecutor

介面中提供submit()方法執行任務。

ThreadPoolTaskExecutor

Spring提供的線程池類。與Java提供的ThreadPoolExecutor線程池類類似,可以配置線程池屬性及拒絕策略。

處理流程與ThreadPoolExecutor一樣。

ThreadPoolTaskScheduler

實現TaskScheduler介面,實現了其介面的調度機制。與Java中的ScheduledThreadPoolExecutor類類似。

多了一個可傳Trigger對象的schedule()方法,可支持Corn表達式進行任務調度。

3 Spring非同步操作

使用@Async註解

標註了@Async註解的方法,稱之為非同步方法。這些方法將在執行的時候,將會在獨立的線程(線程池中獲取)中被執行,調用者無需等待它的完成,即可繼續其他的操作。

@Configuration
@EnableAsync
public class AsyncConfig {
    
}
@Async
public void downloadOrder() throws InterruptedException {
    System.out.println("執行開始時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
    Thread.sleep(10000);
    System.out.println("執行結束時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
}

@Async標註的方法,在同一個類中調用,無效

4 Spring定時任務的幾個實現

4.1 基於@Scheduled註解
@Configuration      //標記為配置類
@EnableScheduling   //開啟定時任務,可以放到啟動類中
public class OrderScheduler {
    //定時任務執行周期,採用Corn表達式
    @Scheduled(cron = "0/5 * * * * ?")
    public void downloadOrder() {
        System.out.println("執行開始時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
        Thread.sleep(10000);
        System.out.println("執行結束時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
    }
}
//並不是每5秒執行一次,上次執行的結果會影響到下次運行。這個相當於10s運行一次了。

@Scheduled註解也可以直接指定時間間隔,如:@Scheduled(fixedRate=5000)

實現本質是基於Java中的ScheduledExecutorService類的schedule方法。

基於@Scheduled註解預設為單線程的。

標註了@Scheduled的方法,執行時是單線程的,也就是說,上次運行的結果會影響到下一次的執行。

image-20200706233720429

4.2 基於SchedulingConfigurer介面
@FunctionalInterface
public interface SchedulingConfigurer {
	void configureTasks(ScheduledTaskRegistrar taskRegistrar);
}
ScheduledTaskRegistrar類

實現SchedulingConfigurer介面,實現configureTasks方法,方法傳入ScheduledTaskRegistrar類對象。

幾種定時任務類型:

  • CronTask:根據Cron表達式執行定時任務
  • TriggerTask:按照Trigger觸發器觸發執行,可以動態改變定時任務的執行
  • FixedRateTask:固定速度執行
  • FixedDelayTask:固定延遲執行
@EnableScheduling //啟動類,設置定時任務開關
@SpringBootApplication
public class MatrixApplication {

    public static void main(String[] args) {
        SpringApplication.run(MatrixApplication.class, args);
    }

}
@Component
public class TestScheduler implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(() -> System.out.println("執行時間:" + LocalDateTime.now()), new CronTrigger("0/2 * * * * ?"));
    }
}

SchedulingConfigurer配置類比@Scheduled註解多了一個TriggerTask,更加靈活,其他的差不多。

4.3 基於註解設定多線程定時任務

@Scheduled註解預設為單線程的,我們可以使用@Async註解啟用多線程。

@Configuration      //標記為配置類
@EnableAsync        //開啟多線程
@EnableScheduling   //開啟定時任務,可以放到啟動類中
public class OrderScheduler {
    //定時任務執行周期,採用Corn表達式
    @Async
    @Scheduled(cron = "0/5 * * * * ?")
    public void downloadOrder() {
        System.out.println("執行開始時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
        Thread.sleep(10000);
        System.out.println("執行結束時間為:" + LocalDateTime.now() + "線程為:" + Thread.currentThread().getName());
    }
}

image-20200706233756167

同一個任務的每一次定時任務執行,都會開闢一個新的線程,不會影響到下一次任務的執行。

4.4 ThreadPoolTaskScheduler

利用線程池實現任務調度。

@Resource
private ThreadPoolTaskScheduler threadPoolTaskScheduler;

@GetMapping("/start")
public void test() {
    threadPoolTaskScheduler.schedule(() -> System.out.println("第" + i + "執行時間:" + LocalDateTime.now()), new CronTrigger("0/2 * * * * ?"));
}
4.5 整合Quartz

定時任務內部的方法可以結合@Async註解使用達到多線程的目的

參考文章
  1. https://www.cnblogs.com/frankyou/p/10135212.html
  2. https://blog.csdn.net/weixin_43168010/article/details/97613895

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 許多同學是不是還在徘徊、猶豫、糾結的階段,想學怕學不好,甚至不知從何入手,下麵這篇文章幫助想轉行前端及想學好Web前端開發的同學們解決心中的困惑。 1HTML的學習 超文本標記語言(HyperTextMark-up Language簡稱HTML)是一個網頁的骨架,無論是靜態網頁還是動態網頁,最終返回 ...
  • 前端埋點主要是為了服務運營人員採集用戶行為數據,進行後續的數據分析工作。 前端監控和埋點能做什麼 數據監控(用戶行為) pv,uv 記錄操作系統 用戶在每一個頁面的停留時間(離開頁面,進入頁面) 用戶進入的入口 用戶在相應頁面的觸發行為,點擊按鈕 性能監控 (js中的performance) 用戶的 ...
  • 綜合來講,Web前端培訓分為HTML5+CSS3、JS交互設計、移動端、伺服器、前端框架、小程式六大模塊,下麵就為大傢具體介紹每個階段學什麼。 第一階段前端核心基礎,讓學員掌握前端基礎知識包括HTML5與CSS的基礎知識和代碼的撰寫會學習PC端網站佈局以及jQuery框架。 第二階段HTML5 + ...
  • web前端現在是一個很熾手可熱的職業,現在前端工程師到底能賺多少錢?月薪3000和30000的工程師到底差在哪?前端的待遇為什麼這麼高? 今天我們來具體分析一下。 web前端的薪資是多少? 我們先用三個數據瞭解一下。 web前端在北京地區的薪資: 北京前端開發工程師平均工資:¥ 18690/月,取自 ...
  • 開發一個 IDE 很難麽?這或許是件很難的事情,但當我們參考 VSCode 的技術構架來看,整個開發流程就會平滑順暢很多,從內核開發、代碼編輯器、視圖結構到插件系統,在這整個技術構架中我們可以看到很多一個 IDE 開發中需要註意的方方面面。如果你對 VSCode 深入研究過,相信可以從中頗受啟發,在 ...
  • 作者:凹凸曼 - Barrior 在 Canvas 中對文本填充水平或垂直的線性漸變可以輕易實現,而帶角度的漸變就複雜很多;就好像下麵這樣,假設文本矩形寬為 W, 高為 H, 左上角坐標為 X, Y。 猜想與答案 給出兩個答案: 正確答案是圖二,因為這樣得出來的坐標生成的漸變最緊接文本矩形邊界,它的 ...
  • Mybatis的sql映射 添加: boolean addUser(User user); <insert id="addUser" parameterType="User"> insert into Users(uname,upass) values(#{uname},#{upass}) </in ...
  • 問題起源 使用SpringCloud構建項目時,使用Swagger生成相應的介面文檔是推薦的選項,Swagger能夠提供頁面訪問,直接在網頁上調試後端系統的介面, 非常方便。最近卻遇到了一個有點困惑的問題,演示介面示例如下(原有功能介面帶有業務實現邏輯,這裡簡化了介面): /** * @descri ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...