背景
プロジェクトの開発中、私たちは多くの場合、定期的なタスクを実行する必要があります。タイミングタスクを通じてそれをうまく達成するのに役立ちます。
一般的に使用されるいくつかのタイミングのタスクフレームワークを比較しましょう。
上記の表からわかるように、Springスケジュールフレームワークには完全な機能があり、シンプルで使いやすいです。春のスケジュールは、中小規模のプロジェクトに完全に適格です。
1。スプリングブート統合スケジュール
1.1 Maven依存関係パッケージの追加
Spring-Boot-Starter Basicモジュールには春のスケジュールが含まれているため、追加の依存関係は必要ありません。
<Dependencies> <Dependency> <groupId> org.springframework.boot </groupid> <artifactid> spring-boot-starter </artifactid> </dependency> <dependency> <deprofency> org.springframework.boot </groupid> <artifactid> spring-boot-statertest </scope> </dependency> </dependencies>
1.2クラスを開始し、スタートアップ注釈を追加します
@EnablesChedulingアノテーションをスプリングブートエントリまたは構成クラスに追加すると、タイミングタスクを有効にすることができます。
@enableScheduling@springbootapplicationpublic class scheduleApplication {public static void main(string [] args){springApplication.run(scheduleapplication.class、args);}}}}1.3。時限タスクを追加します
Springスケジュールの3つのタスクスケジューラの例を示します。
1.3.1クロン式
Linuxの下のCron Expression Time定義ルールと同様です。クロンの式は、以下の図に示すように、時間帯で区切られた6つまたは7つのスペースで構成されています。
一般的な表現:
栗を取る:
10秒ごとに実行される作業()メソッドを追加します。
注:メソッドの実行時間がタスクスケジューリング頻度を超えると、スケジューラは次のサイクルで実行されます。
たとえば、ワーク()メソッドが0秒で実行され、メソッドが12秒間実行されると仮定すると、次にWork()メソッドが実行されるのは20秒です。
@componentpublic class mytask {@scheduled(cron = "0/10 * * * *")public void work(){// task execution logic}}}1.3.2固定インターバルタスク
次のタスク実行時間は、メソッドの最後のタスク実行の終了時間から計算されます。このルールでタスクの定期的な実行を開始します。
栗を取る:
作業()メソッドを追加し、10秒ごとに実行します。
たとえば、Work()メソッドが0秒で実行され始め、メソッドが12秒間実行され、次にWork()メソッドが実行されるのは22秒であると仮定します。
@scheduled(fixeddelay = 1000*10)public void work(){// task execution logic}1.3.3固定周波数タスク
指定された頻度でタスクを実行し、このルールでスケジューリングの定期的な実行を開始します。
栗を取る:
10秒ごとに実行される作業()メソッドを追加します。
注:メソッドの実行時間がタスクスケジューリング頻度を超えると、スケジューラは現在のメソッドが実行された直後に次のタスクを実行します。
たとえば、Work()メソッドが0秒で実行され始め、メソッドが12秒間実行され、次にWork()メソッドが実行されるのは12秒であると仮定します。
@scheduled(fixedrate = 1000*10)public void work(){// task execution logic}2。タスクシェードラースレッドプールを構成します
実際のプロジェクトでは、システムは複数のタイミングタスクを定義する場合があります。次に、複数のタイミングタスクを独立して実行し、並行して実行できます。
org.springframework.scheduling.config.scheduledtaskRegistrarソースコードを見ると、Springはデフォルトでシングルスレッドプールを作成することがわかります。これは、マルチタスクにとって致命的です。複数のタスクが同時に実行される(または同時に実行する必要がある)場合、タスクスケジューラは時間のドリフトを経験し、タスクの実行時間が不確かになります。
Protected void scheduletasks(){if(this.taskscheduler == null){this.localexecutor = executors.newsinglethreadscheduledexecutor(); this.taskscheduler = new concurrenttaskscheduler(this.localexecutor);} // omit ...}}2.1カスタムスレッドプール
SchedulingConfigurerインターフェイスを実装するための構成クラスを追加しました。 ConfigureTasksメソッドを書き換え、TaskRegistrarを介してカスタムスレッドプールを設定します。
@configurationpublic class scheduleconfig ScheduleingConfigurer {@OverridePublic void ConfigureTasks(ScheduleDtaskRegistrar TaskRegistrar){taskRegistrar.setscheduler(taskexecutor());}@bean(Destrymethod = "Shutdown")Public Execustor Taskexutor() executors.newscheduledthreadpool(20);}}3。実際のアプリケーションの問題
3.1 Webアプリケーションの起動とシャットダウンの問題
サービスが停止したときに、春までbeanが自動的にアンロード(破壊されます)が自動的にアンロードされる(破壊)ことがわかっています。ただし、スレッドはJVMレベルであるため、ユーザーがWebアプリケーションでスレッドを起動する場合、このスレッドのライフサイクルはWebアプリケーションと一致しません。つまり、Webアプリケーションが停止したとしても、スレッドはまだ終了しません(死)。
解決:
1)現在のオブジェクトはスプリングまで初期化されます
Springがインスタンスをアンインストールする(破壊)場合、インスタンスの破壊方法が呼び出されます。 DisapsableBean Interface Overriding Destroy Methodを実装することにより実装されます。破壊方法のスレッドを積極的に閉じます。
@ComponentPublic Class MyTask Implestion DesurtyBean {@OverridePublic void Destroy()Throws Exception {// ThreadまたはThread Poolswooltaskscheduler scheduler =(threadPooltasksCheduler)ApplicationContext.getBean( "Schedumerer"); Schedul.shutdown();} // omit ...2)現在のオブジェクトはスプリングまで初期化(管理されていません)
その後、サーブレットコンテキストリスナーを追加して、サーブレットサービスが停止したときにスレッドを積極的に閉じることができます。
パブリッククラスmytasklistenterは、servletcontextlistener {@overridepublic contextdestroyed(servletcontextevent arg0){//閉じるスレッドまたはスレッドプール} // omit ...}}を実装しています。3.2分散展開の問題
実際のプロジェクトでは、私たちのシステムは通常、クラスター、分散、または災害復旧に展開されます。その後、タイミングタスクには並行性の問題がある可能性があります。つまり、同じタスクが複数のサーバーで同時に実行されている可能性があります。
ソリューション(分散ロック):
1)データベーステーブルをロックします
2)キャッシュミドルウェア
3)Zookeeperを通じて実装
要約:
春のスケジュールは、シンプルで高速で、効率的で安定したタイミングタスクフレームワークを提供します。ただし、スレッドと分散展開の問題のライフサイクルを考慮する必要があります。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。