Javaプログラミング・ロジック(80) - これらのピットの定期的なタスク

このセクションでは、タスクのタイミングは、タイミングシナリオのタスクのような、非常に大きい調べ。

  • 目覚まし時計プログラムまたはタスクリマインダ、または警告にも指定された日付に時間Jiaochuangのクレジットカードを指定します
  • 異常なイベントのためのシステムのデータ取得の下に随時、システムの監視、警報
  • 統計システム、一般的に午前中に様々な指標のいくつかの時間統計データは昨日

Javaでは、タイミングタスクを達成するための2つの方法があります。

  • パッケージタイマーとTimerTaskをjava.utilの使用
  • ScheduledExecutorServiceで使用するJavaおよび請負

彼らの基本的な使い方は比較的簡単ですが、あなたがそれらについて十分に知っていない場合、それは、ここでは、我々は彼らの使用だけでなく、これらの原則ピットを導入する必要があり、それらのいくつかの罠に陥ることは非常に簡単です。

時間和時間タスク

基本的な使い方

TimerTaskをタイミングタスクを表し、それは実装のRunnableという抽象クラスで、タイミングタスクはrunメソッドを実装して、特定のクラスの継承が必要です。

タイマーが実行されるタスクのタイミングとスケジューリングのために責任がある具象クラス、である、それは以下の主な方法があります。 

コードをコピー
//タスクのタスク実行に時間が絶対時間を指定し
ます。public voidスケジュール(TimerTaskをタスク、日付時刻)
現在時刻にタスクを実行するために、遅延(ミリ秒)のタスクの後に//遅延を
公共のボイドスケジュール(TimerTaskをタスク、長い遅延) 
を繰り返し//固定遅延、最初の「本当の」実行時間を加えた期間前に計画、実行時間の後、FIRSTTIMEの実行時間をスケジュールし
ます。public voidスケジュール(TimerTaskをタスク、日付FIRSTTIME、長い期間)
と同じ固定遅延を繰り返し//、最初の実行時間は、現在の時間プラス遅延で
ます。public voidスケジュール(TimerTaskをタスク、長い遅延、長い期間)
最初に「前回の計画実行時間後、FIRSTTIMEの実行時間を予定し//繰り返し固定周波数、計画「の実行時間を加えた期間
ます。public void scheduleAtFixedRate(TimerTaskをタスク、日付FIRSTTIME、長い期間)
//は同じ固定周波数、電流の時間のための計画の最初の実装に加えて、遅延時間繰り返し
ます。public void scheduleAtFixedRate(TimerTaskをタスク、長い遅延を、長い期間)
コードをコピー

注固定周波数差(固定レート)との固定遅延は、(固定遅延)、繰り返し実行されるが、比較的タスク実行時間は同じではないことは、最後のタスクに基づいて固定遅延、 「本物」の実行時間は、何らかの理由で、最後のミッションが遅れた場合には、固定周波数動作に十分な時間を作るしようとしながら、この使命は、延期され、カウントします。

また、最初のスケジュール実行時間FIRSTTIMEが過去の時間であれば、タスクはすぐに実行されることに注意してくださいは、固定遅延タスクのために、次のタスクは、最初の実行時間に基づいて計算され、固定用されますタスクの頻度は、それがFIRSTTIMEからカウントを開始します、時間が現在の時刻を超えるまで、そのため連続運転を何度も追加したり、過去の一定期間の後にすることが可能です。

ビューのいくつかの簡単な例の特定のポイントを経由して私たちの次。

基本的な例

簡単な例を見てください:

コードをコピー
パブリッククラスBasicTimer { 
    静的クラスDelayTaskはTimerTaskを{延び
        
        @Override 
        公共ボイドラン(){ 
            System.out.printlnは( "遅延タスクを"); 
        } 
    } 
    
    公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー
        タイマタイマ=新しいタイマを(); 
        timer.schedule(新しいDelayTask()、1000); 
        Thread.sleep(2000); 
        timer.cancel(); 
    } 
}
コードをコピー

Timerオブジェクトを作成し、DelayTask 1秒を実行し、そして最終的にキャンセルメソッドタイマーを呼び出して、すべてのスケジュールされたタスクをキャンセルします。

固定遅延の簡単な例を参照してください。

コードをコピー
パブリッククラスTimerFixedDelayは{ 

    静的クラスLongRunningTaskが延びTimerTaskを{ 
        @Override 
        ます。public void実行(){ 
            試み{ 
                のThread.sleep(5000); 
            }キャッチ(InterruptedExceptionある電子){ 
            } 
            のSystem.out.println( "長い完成実行")。
        } 
    } 

    静的クラスFixedDelayTaskが延びるTimerTaskを{ 
        @Override 
        公共ボイドラン(){ 
            System.out.printlnは(のSystem.currentTimeMillis())。
        } 
    } 

    公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー
        タイマタイマ=新しいタイマを();

        timer.schedule(新しいLongRunningTask()、10); 
        timer.schedule(新しいFixedDelayTask()、100、1000); 
    } 
}
コードをコピー

2つのがあり、タイミングタスク、最初の実行時間がありますが、それは、第二の後、最初に実行するために、第二が繰り返し実行され、5秒かかります。プログラムを実行し、2番目のタスクが唯一の第二回実行、最初のタスクの実行終了後に実行を開始しますでしょう。

上記のコードは、固定周波数である場合に代替的に、すなわち、コードは次のようになります。

コードをコピー
パブリッククラスTimerFixedRateは{ 

    静的クラスLongRunningTaskが延びTimerTaskを{ 
        @Override 
        ます。public void実行(){ 
            試み{ 
                のThread.sleep(5000); 
            }キャッチ(InterruptedExceptionある電子){ 
            } 
            のSystem.out.println( "長い完成実行")。
        } 
    } 

    静的クラスFixedRateTaskが延びるTimerTaskを{ 

        @Override 
        公共ボイドラン(){ 
            System.out.printlnは(のSystem.currentTimeMillis())。
        } 
    } 

    公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー
        タイマタイマ=新しいタイマを();

        timer.schedule(新しいLongRunningTask()、10); 
        timer.scheduleAtFixedRate(新しいFixedRateTask()、100、1000); 
    } 
}
コードをコピー

プログラムを実行し、同じ2番目のタスクのみを実行するための最初のタスクの終了時に実行されますが、それは、次のような突然の実行5回、出力のすべてをいっぱいになります前に番号が実行されていません。

コードをコピー
長い終わっ稼働
1489467662330 
1489467662330 
1489467662330 
1489467662330 
1489467662330 
1489467662419 
1489467663418
コードをコピー

基本的な

内部タイマは二つの部分、タスクキューとタイマースレッドで構成されています。タスクキューは、次の実行優先順位付けの時間に応じて、優先度キューヒープベースの実装です。タイマースレッドは、すべてのスケジュールされたタスクの実行を担当し、Timerオブジェクトがそう、一つだけタイマースレッドを持っていることを強調する必要があるが、上記の例では、タスクが遅延されます。

タイマーがスレッドメインループであったタスクがあり、計画実行時間が現在の時間に等しいよりも小さい場合がキューにタスクがないか、スリープ状態に、最初のタスクを遅延させない場合は、キューからキューを仕事を取る、それが実行されます。スリープ・キュー中に新しいタスクと新しいタスクを追加する場合は、最初のタスクで、タイマースレッドが起こされるだろうと再確認。

タスクを実行する前に、タイマースレッドは、タスクが周期的なタスクであるか否かを判断し、もしそうであれば、次の実行の時間を設定し、固定遅延タスク、次の実行時間と現在の時間帯の優先度キューに追加しますタスクの固定周波数のため、次回実行時間は、最後の計画プラス期間の実行時間です。

固定遅延タスク、タスクの実行、後のタスクの実行ではなく、およびトークバックの前に、現在の遅延時間の相対的なため、現在のタスクの実行が行われる前に計画が次の課題であることが強調されるべきです計算ScheduledExecutorService固定遅延は、通常予想とより一致している計算法とは異なります。

一方、タスクの固定周波数のため、それは常に予定番組の最初に基づいており、従って、それが登場一度に多くの任務を実行する前の例の場合である可能性が高いです。

無限ループ

A Timerオブジェクトは一つだけタイマースレッド、定期的なタスクは時間がかかりすぎることはできませんが、例の無限ループ、一見することができないことを意味しています

コードをコピー
パブリッククラスEndlessLoopTimerは{ 
    静的クラスLoopTaskが延びTimerTaskを{ 

        @Override 
        ます。public void実行(){ 
            ながら、(真){ 
                試み{ 
                    // ...执行任务
                    のThread.sleep(1000); 
                }キャッチ(InterruptedExceptionある電子){ 
                    e.printStackTrace(); 
                } 
            } 
        } 
    } 

    //永远也没有机会执行
    静的クラスExampleTaskはTimerTaskをを拡張{ 
        @Override 
        公共ボイドラン(){ 

            System.out.printlnは( "こんにちは"); 
        } 
    }

    公共の静的な無効メイン(文字列[]引数)が例外:InterruptedExceptionをスロー{ 
        タイマタイマ=新しいTimer(); 
        timer.schedule(新しいLoopTask()、10); 
        timer.schedule(新しいExampleTask()、100); 
    } 
}
コードをコピー

最初のタイミングタスクは、後続タスクExampleTaskのタイミングで実行する機会を持っていることはありません、無限ループです。

例外処理

タイマースレッドについて、また、我々は、タスクを実行するすべてのメソッドの実装では非常に重要なポイントを強調するために必要な、実行が例外をスローすると、タイマースレッドは、すべてのスケジュールされたタスクがキャンセルされるように終了します。私たちは、簡単な例を見て:

コードをコピー
パブリッククラスTimerExceptionは{ 

    静的クラスTaskAが延びるTimerTaskを{ 
        
        @Override 
        公共ボイドラン(){ 
            System.out.printlnは( "タスクA")。
        } 
    } 
    
    静的クラスTaskBが延びるTimerTaskを{ 
        
        @Override 
        公共ボイドラン(){ 
            System.out.printlnは( "タスクB")。
            新しいのRuntimeExceptionを投げます(); 
        } 
    } 

    公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー
        タイマタイマ=新しいタイマを(); 
        timer.schedule(新しいTaskA()、1、1000); 
        timer.schedule(新しいTaskB()、2000、1000); 
    } 
}
コードをコピー

TaskAは、1秒に1回実行すると予想、しかしTaskBは、スケジュールされたタスクにつながる、例外がスローされます、プログラムの終了をキャンセルされ、画面出力は次のようになります。

コードをコピー
タスクA 
タスクA 
タスクBの
スレッドの例外"タイマー-0" java.lang.RuntimeException 
    laoma.demo.timer.TimerException $ TaskB.run(TimerException.java:21)で
    java.util.TimerThread.mainLoop(Timer.javaで:555)
    java.util.TimerThread.runで(Timer.java:505)
コードをコピー

あなたは、各スケジュールされたタスクは、互いに干渉しないしたいのであれば、runメソッド内のすべての例外をキャッチしてください。

概要

見ることができ、タイマ/ TimerTaskをの基本的な使用は比較的簡単ですが、我々は注意を払う必要があります:

  • 唯一つのスレッドの背後で実行されています
  • タスクは、固定周波数の後に遅延され、即座に、十分なアップ回数を何回も実行することができます
  • タスクが実行される前に、遅延タスクは、比較的遅延時間を固定します
  • タイミングタスクで無限ループを使用しないでください。
  • 未処理の例外は、すべての定期的なタスクがキャンセルされたタスクの原因を時限

ScheduledExecutorService   

インターフェイスとクラス定義

何らかの問題タイマー/ TimerTaskをの、Javaと契約ScheduledExecutorServiceの導入のために、それは以下のように定義されたインタフェースは、次のとおりです。

コードをコピー
インタフェースScheduledExecutorServiceは拡張ExecutorServiceの{公共
    //シングル、実行コマンドの遅延時間後に
    公共ScheduledFutureスケジュール(Runnableをコマンド、長い遅延、TimeUnitで単位)<?>; 
    //シングル、実行後の遅延時間呼び出し可能な
    パブリック<V> ScheduledFuture <V>スケジュール(呼び出し可能<V>コーラブル、長時間の遅延、TimeUnitでユニット); 
    //固定周波数が繰り返し実行される
    パブリックScheduledFuture scheduleAtFixedRate(Runnableをコマンド、長い <?> initialDelayの、長い期間、TimeUnitで単位)。 
    //固定遅延を繰り返す
    <?>公共ScheduledFuture scheduleWithFixedDelay(Runnableをコマンド、initialDelayの長い、長い遅延、TimeUnitでユニット); 
}
コードをコピー

彼らの戻り値の型はScheduledFutureあり、それは未来を拡張し、遅延、追加のメソッドが定義されていないインタフェースです。セマンティクスタイマーこれらの方法の大部分は、実質的に類似しています。固定周波数のタスクのために、initialDelayの、二度目initialDelayの+の期間、第がinitialDelay + 2 *期間の最初の実行時間の後、など。しかし、最初に実行されるタスクプラス遅延の終了後に二度目のため、initialDelayの後に初めて、タスク実行カウントから開始することで、固定遅延タスク、ため。タイマーとは異なり、それは最初の実行の時のように絶対的な時間をサポートしていません。

ScheduledExecutorServiceメイン実装クラスは、スレッドプールThreadPoolExecutorのサブクラスでScheduledThreadPoolExecutorのは、その主なコンストラクタスレッドプールの実装はに基づいていることです。

公共のScheduledThreadPoolExecutor(int型corePoolSize) 

また、施工方法がThreadPoolExecutorを意味し、ThreadFactoryとのRejectedExecutionHandlerを取ることができ、我々は詳細には触れません。

スレッドの最大数は、それがcorePoolSizeが0に設定されていても、それは少なくとも一つのスレッドを実行しますが、効果はありませんので、そのタスクキューは、無制限の優先度キューです。

執行ファクトリクラス以下のように、のScheduledThreadPoolExecutorの作成を容易にするために、いくつかの便利な方法を提供します。

コードをコピー
//シングルスレッドタスク実行タイミングサービス
のpublic static ScheduledExecutorService newSingleThreadScheduledExecutor()
パブリック静的ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
//マルチスレッドタスク実行タイミングサービス
のpublic static ScheduledExecutorService newScheduledThreadPool(INT corePoolSize)
のpublic static ScheduledExecutorService newScheduledThreadPool(INT corePoolSize、ThreadFactory threadFactory )
コードをコピー

基本的な例

あなたは、実行スケジュールされたタスクの複数のスレッドを持つことができるので、作業は一般的に長時間実行遅延の作業ではありません、例えば、前回のTimerFixedDelayため、次のように読めば:

コードをコピー
パブリッククラスScheduledFixedDelay { 
    静的クラスLongRunningTask実装Runnableを{ 
        @Override 
        ます。public void実行(){ 
            試み{ 
                のThread.sleep(5000); 
            }キャッチ(InterruptedExceptionある電子){ 
            } 
            のSystem.out.println( "長い完成実行")。
        } 
    } 

    静的クラスFixedDelayTask実装Runnableを{ 
        @Override 
        公共ボイドラン(){ 
            System.out.printlnは(のSystem.currentTimeMillis())。
        } 
    } 

    公共の静的な無効メイン(文字列[]引数)が例外:InterruptedExceptionをスロー{ 
        ScheduledExecutorServiceタイマ= Executors.newScheduledThreadPool(10)。
        timer.schedule(新しいLongRunningTask()、10、TimeUnit.MILLISECONDS)。
        timer.scheduleWithFixedDelay(新しいFixedDelayTask()、100、1000年、
                TimeUnit.MILLISECONDS)。
    } 
}
コードをコピー

再実行、2番目のタスクは、最初のタスクが遅れていることはありません。

スケジュールされたタスクは、ミッションの後ろに一つだけのスレッドが、私たちは例を見ても、キャンセルされた全体また、異なるタイマーは、例外が単一のタイミングタスクにはなりません。

コードをコピー
パブリッククラスScheduledException { 

    静的クラスTaskA実装Runnableを{ 

        @Override 
        ます。public void実行(){ 
            System.out.printlnは( "タスクA"); 
        } 
    } 

    静的クラスTaskB実装Runnableを{ 

        @Override 
        公共ボイドラン(){ 
            System.out.printlnは( "タスクB")。
            新しいのRuntimeExceptionを投げます(); 
        } 
    } 

    公共の静的な無効メイン(文字列[]引数)を{例外:InterruptedExceptionをスロー
        ScheduledExecutorServiceタイマ=エグゼキュータ
                .newSingleThreadScheduledExecutor()。
        timer.scheduleWithFixedDelay(新しいTaskA()、0、1、TimeUnit.SECONDS)。
        timer.scheduleWithFixedDelay(新しいTaskB()、2、1、TimeUnit.SECONDS)。
    } 
}
コードをコピー

TaskAとTaskBはTaskBが実行さ2秒後に、1秒に1回実行されますが、次のようなスロー、出力画面上で実行されています。

コードをコピー
タスクA 
タスクA 
タスクB 
タスクA 
タスクA 
...
コードをコピー

このショーは、定期的なタスクTaskBが取り消​​されたことが、TaskAは、それらが同じスレッドによって実行された場合でも、影響を受けることはありません。しかし、それはタイマー異なるが、例外がスローされないことを強調すべきである、TaskB例外はどこにも反映されませんでした。そのため、同様のタイマータスクで、あなたはすべての例外をキャッチする必要があります。

基本的な

タイマーとアイデアのScheduledThreadPoolExecutorの実現には、ヒープベースのプライオリティキューは、スケジュールされたタスクを実行する保存、その主な違いは、そこにある、基本的に同様です。

  • それは、スレッド・プールでの背後にある、あなたが実行するタスクの複数のスレッドを持つことができます
  • より合理的なタスクの固定遅延のために、実行したタスクの次の実行を設定するための時間です
  • それは、繰り返しタスクの場合でも、タスクの実行スレッドは、タスクをスケジュールし、他のタスクのタイミングに影響を与えないだろう異常な変化で行われたすべてのタスクをキャプチャしませんが、タスクはもはや再スケジュールされ、発生した例外です

概要

このセクションでは、定期的なタスクでのJavaの2つの実装、タイマーやScheduledExecutorService、落とし穴タイマーの一部に特別な注意を払う必要性を説明し、練習をScheduledExecutorServiceをお勧めします。

彼らの共通の制限は、夕方18:00から夜10時00分に、タイミングは例えば、有能な複雑なタスク・スケジューリングではないことを毎週月曜日と水曜日で、すべての半分の1時間に1回行いました。この要求と同様に、我々は、セクション32で処理する前に、日付と時刻を使用することができ、セクション33は、説明、または石英のような、より強力なサードパーティ製のライブラリを、(使用http://www.quartz-scheduler.org/ )。

同時実行アプリケーションでは、一般的に我々は、このような様々なコンカレント・コンテナーは、スレッドと、自分の管理の間の同期を避けるために、前のセクション、サービスおよびタスク実行スレッドプールに説明するが、個々のケースのように、ハイレベルのサービスを利用しようとする必要があります自分のスレッド管理と同期が必要である、そして、前のセクションに加えて、同期、待機/通知の使用を導入して、基本的なツールを表示した状態をロックし、Javaとの契約も達成を容易にするために、いくつかの先進的な同期とコラボレーションツールを提供同時実行アプリケーションは、それらについて学ぶために、次のセクションで私たちをみましょう。

おすすめ

転載: www.cnblogs.com/ivy-xu/p/12375495.html