プログラミングプロセス中にいくつかの簡単なタイミングタスクを実行する必要がある場合は、複雑な制御を行う必要はありません。 JDKのタイムタイミングタスクを使用してそれを実現することを検討できます。次のLZは、その原理、例、およびタイマーの欠陥に基づいてJavaタイマータイマーを分析します。
1。はじめに
Javaでは、タイマーとTimertaskのクラスで完全なタイミングタスクを完了する必要があります。これは、それらがAPIで定義される方法です。タイマー:それを使用して、スレッドが背景スレッドで実行されるタスクを後でアレンジするツール。タスクは一度実行することも、繰り返し実行することもできます。 Timertaskによってスケジュールされるタスク:実行または繰り返されるタスクとしてタイマー。タイマーは、バックグラウンドスレッドで指定されたタスクを実行するために計画するために使用されるタイマーツールであり、サブクラスがタイマーによって計画できるタスクを表す抽象クラスであるTimerTaskが使用されるタイマーツールであることを理解できます。
タイマークラスは、ツールクラスタイマーに4つのコンストラクターメソッドを提供します。各コンストラクターはタイマースレッドを起動します。同時に、タイマークラスは、複数のスレッドが外部同期なしで単一のタイマーオブジェクトを共有できるようにすることができるため、タイマークラスはスレッドセーフです。ただし、各タイマーオブジェクトは、すべてのタイマータスクを順番に実行するために使用される単一のバックグラウンドスレッドに対応するため、一般的に、スレッドタスクの実行に費やされる時間は非常に短いはずです。ただし、特別な状況により、特定のタイマータスクの実行時間は長すぎるため、タイマータスクの実行スレッドが「排他的に」行われ、後続のすべてのスレッドが実行されるのを待つ必要があります。後で特定の状況を分析します。
プログラムがタイマーを初期化すると、タイミングタスクは設定された時間に従って実行されます。タイマーは、次のように、さまざまな状況に適応するための複数の過負荷があるスケジュール方法を提供します。
スケジュール(TimerTaskタスク、日付):指定された時間に指定されたタスクの実行をスケジュールします。
スケジュール(TimerTaskタスク、初めて、長期間):指定されたタスクをスケジュールして、指定された時間に繰り返し固定遅延実行を開始します。
スケジュール(Timertaskタスク、長い遅延):指定された遅延後に実行される指定されたタスクをスケジュールします。
スケジュール(Timertaskタスク、長い遅延、長期):指定される指定されたタスクをスケジュールして、指定された遅延後に繰り返し固定遅延されます。
同時に、ScheduleAtFixEdrateメソッドも過負荷になります。 ScheduleAteTfixEdrateメソッドはスケジュールと同じですが、焦点は異なり、違いは後で分析されます。
scheduleatfixedrate(timertaskタスク、初めての日付、長期):指定されたタスクを、指定された時間に固定レートで繰り返し実行するスケジュールを設定します。
ScheduleAteAtFixEdrate(TimerTaskタスク、長い遅延、長期間):指定されたタスクをスケジュールして、指定された遅延後に繰り返し固定料金実行を開始します。
Timertask
TimerTaskクラスは、実行または繰り返されるタスクとしてタイマーによって配置された抽象クラスです。抽象メソッドrun()メソッドがあり、対応するタイマータスクによって実行される操作を実行するために使用されます。したがって、各特定のタスククラスはティマタスクを継承し、run()メソッドをオーバーライドする必要があります。
さらに、2つの非アブストラクトメソッドがあります。
Boolean Cancel():このタイマータスクをキャンセルします。
Long ScheduleDexecutionTime():このタスクの最新の実際の実行のスケジュールされた実行時間を返します。
2。例
2.1。タイミングタスクを実行する遅延時間を指定します
Public Class Timertest01 {タイマータイマー; public timertest01(int time){timer = new Timer(); Timer.schedule(new timertasktest01()、time * 1000); } public static void main(string [] args){system.out.println( "Timer Begin ...");新しいtimertest01(3); }} public class timertasktest01 extends timertask {public void run(){system.out.println( "Time's Up !!!"); }}実行結果:
最初の印刷:
タイマーの始まり....
3秒で印刷:
時間があります!!!
2.2。指定された時間にタイミングタスクを実行します
Public Class Timertest02 {タイマータイマー; public timertest02(){date time = getTime(); System.out.println( "時間=" + time); Timer = new Timer(); Timer.schedule(new timertasktest02()、time); } public date getTime(){Calendar Calendar = Calendar.GetInstance(); calendar.set(calendar.hour_of_day、11); calendar.set(calendar.minute、39); calendar.set(Callearn.second、00); date time = calendar.getTime();返品時間; } public static void main(string [] args){new timertest02(); }} public class timertasktest02 extends timertask {@override public void run(){system.out.println( "指定された時間にスレッドタスクを実行..."); }}時間が11:39:00に達すると、スレッドタスクは実行されます。もちろん、それはその時間よりも大きい場合でも実行されます! !実行結果は次のとおりです。
指定された時間=火曜日6月10日11:39:00 CST 2014スレッドタスクを実行する指定時間...
2.3。指定された時間を遅らせた後、タイミングタスクは指定された間隔時間に実行されます。
Public Class Timertest03 {タイマータイマー; public timertest03(){timer = new Timer(); Timer.schedule(new timertasktest03()、1000、2000); } public static void main(string [] args){new timertest03(); }} public class timertasktest03 extends timertask {@override public void run(){date date = new date(this.scheduledexecutiontime()); system.out.println( "このスレッドを実行する時間は" + date); }}実行結果:
このスレッドを実行する時間は次のとおりです。火曜日10日6月10日CST 2014このスレッドを実行する時間は次のとおりです。 2014このスレッドを実行する時間は次のとおりです。
このスレッドタスクの場合、タスクを停止しないと実行され続けます。
上記の3つの例では、LZはそれを一時的に実証したばかりで、ScheduleatfixEdrateメソッドの例を説明しませんでした。実際、この方法はスケジュール方法と同じです!
2.4。スケジュールを分析し、scheduleatfixedrateを分析します
(1)スケジュール(Timertaskタスク、日付時刻)、スケジュール(Timertaskタスク、長い遅延)
どちらの方法でも、指定されたスケジュールexecutiontime <= SystemCurrentTimeの場合、タスクはすぐに実行されます。 ScheduleDexeCutionTimeは、タスクの過度の実行のために変更されません。
(2)スケジュール(Timertaskタスク、初めて、長期間)、スケジュール(Timertaskタスク、長い遅延、長期間)
これらの2つの方法は、上記の2つとは少し異なります。前述のように、以前のタスクが長い間実行されているため、タイマータイマータスクは遅延します。これらの2つの方法では、実行された各タスクのスケジュールされた時間は、前のタスクの実際の時間、つまりスケジュールされたexecutiontime(n+1)= rewexecutiontime(n)+期間とともに変更されます。つまり、NTHタスクが何らかの状況によりこの実行時間プロセスを引き起こし、最後にSystemCurrentTime> = ScheduleDexeCutionTime(N+1)を引き起こす場合、これはN+1タスクであり、時間のために実行されません。実行前にn番目のタスクが実行されるのを待ちます。これにより、これは必然的にn+2実行実装のリリースと変更、つまりスケジュールされた除外時間(n+2)= reelexecutiontime(n+1)+期間につながります。したがって、これらの2つの方法は、ストレージ間隔時間の安定性により多くの注意を払っています。
(3)scheduleatfixedrate(Timertaskタスク、初めて、長期間)、Scheduleatfixedrate(Timertaskタスク、長い遅延、長期)
前述のように、Scheduleatfixedrateとスケジュールの方法の焦点は異なります。スケジュールメソッドは、保存間隔時間の安定性に焦点を当てていますが、ScheduleAteTFixRateメソッドは、実行周波数の安定性の維持により重点を置いています。なぜそう言うのですか、理由は次のとおりです。スケジュール方法では、以前のタスクの遅延は、その後のタイミングタスクの遅延を引き起こしますが、ScheduleAtFixEdrateメソッドはそうではありません。 n番目のタスクの実行時間が長すぎる場合、SystemCurrentTime> = ScheduleDexeCutionTime(n+1)では、すぐにN+1タスクを実行するのを待つことはありません。したがって、ScheduleAtFixEdrateメソッドの実行時間の計算方法はスケジュールとは異なりますが、ScheduleDexeCutionTime(n)= FirstExecutetime +n*期間、計算方法は永遠に変化しません。したがって、ScheduleAteTedRateは、実行周波数を安定させることに重点を置いています。
3。タイマーの欠陥
3.1。タイマーの欠陥
タイマータイマーは、時間(指定された時間にタスクを実行)、遅延(5秒でタスクを遅らせる)、および定期的にタスクを実行(1秒でタスクを実行)できますが、タイマーにはいくつかの欠点があります。まず、タイマーのスケジューリングに対するサポートは、相対的な時間ではなく絶対時間に基づいているため、システム時間の変化に非常に敏感です。第二に、タイマースレッドは例外をキャッチしません。未チェックの例外がTimerTaskによってスローされた場合、タイマースレッドが終了します。同時に、タイマーはスレッドの実行を再開せず、タイマースレッド全体がキャンセルされると誤って信じられます。同時に、まだ実行されていないようにスケジュールされているTimertaskは実行されなくなり、新しいタスクをスケジュールすることはできません。したがって、TimerTaskが未確認の例外をスローする場合、タイマーは予測不可能な動作を生成します。
(1)タイマー管理時間遅延欠陥。タイムされたタスクを実行するときに、タイマーが1つのスレッドタスクのみを作成する前に。複数のスレッドがある場合、スレッドのいずれかがスレッドタスクの実行時間を何らかの理由で長すぎると、2つのタスク間の間隔が発生する場合、いくつかの欠陥が発生します。
Public Class Timertest04 {プライベートタイマータイマー;パブリックロングスタート; public timertest04(){this.timer = new Timer(); start = system.currenttimemillis(); } public void timerone(){timer.schedule(new timertask(){public void run(){system.out.println( "timerone invoked、the time:" +(system.currenttimemillis() - start); try {thread.sleep); // thread Sleeps 3000} catchs(e.print exedexedex(); }}}}、1000); } public void timertwo(){timer.schedule(new timertask(){public void run(){system.out.println( "timerone invoked、the time:" +(system.currenttimemillis() - start);}}}}、3000); } public static void main(string [] args)スロー例外{timertest04 test = new timertest04(); test.timerone(); test.timertwo(); }}私たちの通常の考え方によれば、ティマートーは3秒後に実行されるべきであり、結果は次のとおりです。
Timeroneが呼び出されました、The Time:1001 Timeroneが呼び出されました、The Time:3001
しかし、物事は私の期待に反しました。タイムローンは眠り(4000)、4秒眠り、タイマーはタイマー内にあり、タイムーンが間隔を超えるのに必要な時間を引き起こします。結果:
Timeroneが呼び出されました、時間:1000 Timeroneが呼び出されました、時間:5000
(2)タイマーは例外欠陥を投げます。 TimerTaskがRuntimeExceptionを投げると、タイマーはすべてのタスクの実行を終了します。次のように:
Public Class Timertest04 {プライベートタイマータイマー; public timertest04(){this.timer = new Timer(); } public void timerone(){timer.schedule(new timertask(){public void run(){throw new runtimeexception();}}、1000); } public void timertwo(){timer.schedule(new timertask(){public void run(){system.out.println( "実行??");}}、1000); } public static void main(string [] args){timertest04 test = new timertest04(); test.timerone(); test.timertwo(); }}ランニング結果:Timeroneは例外をスローし、Timertwoタスクを終了させます。
com.chenssy.timer.timertest04 $ 1.run(timertest04.java:25)のjava.util.timerthread.mainloop(timer.java:555)のcom.chenssy.timer.timertest04 $ 1.run(timertest04.java:555)のスレッド「タイマー-0」java.lang.runtimeexceptionの例外
タイマーの欠陥については、ScheduledThreadPoolexecutorを代替品と見なすことができます。タイマーは絶対時間に基づいており、システム時間に対してより敏感ですが、スケジュールされたThreadPoolexecutorは相対的な時間に基づいています。タイマーは内部的に単一のスレッドであり、スケジュールされたthreadpoolexecutorは内部的にスレッドプールであるため、複数のタスクの同時実行をサポートできます。
3.2。タイマーをScheduleDexecutorServiceに置き換えます
(1)問題を解決します。
public class ScheduleDexecutortest {private ScheduleDexecutorService Scheduexec;パブリックロングスタート; ScheduleDexecutortest(){this.scheduexec = executors.newscheduledthreadpool(2); this.start = system.currenttimemillis(); } public void timerone(){scheduexec.schedule(new runnable(){public void run(){system.out.println( "timerone、the time:" +(system.currenttimemillis() - start); try {thread.sleep); }、1000、timeunit.milliseconds); } public void timertwo(){scheduleexec.schedule(new runnable(){public void run(){system.out.println( "timertwo、the time:" +(system.currenttimemillis() - start);}}}}、timeunit.milliseconds); } public static void main(string [] args){scheduledexecutortest test = new ScheduleDexecutortest(); test.timerone(); test.timertwo(); }}実行結果:
Timerone、The Time:1003 Timertwo、The Time:2005
(2)問題2を解決します
public class ScheduleDexecutortest {private ScheduleDexecutorService Scheduexec;パブリックロングスタート。 ScheduleDexecutortest(){this.scheduexec = executors.newscheduledthreadpool(2); this.start = system.currenttimemillis(); } public void timerone(){scheduexec.schedule(new runnable(){public void run(){throw new runtimeexcection();}}、1000、timeunit.milliseconds); } public void timertwo(){scheduleexec.scheduleatfixedrate(new runnable(){public void run(){system.out.println( "timertwo invoked ....");}}、2000,500、timeunit.milliseconds); } public static void main(string [] args){scheduledexecutortest test = new ScheduleDexecutortest(); test.timerone(); test.timertwo(); }}実行結果:
Timertwoが呼び出されました... Timertwoが呼び出されました... Timertwoが呼び出されました... Timertwoが呼び出されました... Timertwo Invoked ... Timertwoは呼び出されました... Timertwoが呼び出されました... Timertwoが呼び出されました... Timertwo Invoked .......... Timertwo ............
4.タイマーを使用してボールを達成します
シミュレーションブックの例はピンボールを行いました。これは、キャンバスの指定された位置で複数の円を描くことでした。また、遅延期間の後、近くの位置で再描画されました。ボールを動かしているように見せ、JSPINNERコンポーネントを介して遅延を調整して、ボールの動き速度を制御します。
ballscanvas.java
パブリッククラスのballscanvasは、canvasを拡張し、actionlistener、focuslistener {プライベートボールボール[]; //複数のボールプライベートタイマータイマー。プライベート静的クラスボール{int x、y; //カラーカラーを調整します。 //カラーブールアップ、左; //モーションボールの方向(int x、int y、color){this.x = x; this.y = y; this.color = color; up = left = false; }} public ballscanvas(color colors []、int delay){//色を初期化して遅延し、balls = new ball [colors.length]; for(int i = 0、x = 40; i <colors.length; i ++、x+= 40){balls [i] = new ball(x、x、colors [i]); } this.addfocuslistener(this);タイマー=新しいタイマー(遅延、これ); //タイマーオブジェクトを作成し、遅延delay timer.start()を指定します。 } // [遅延] public void setdelay(int delay){timer.setdelay(delay); } // public void paint(graphics g){for(int i = 0; i <balls.length; i ++){g.setcolor(balls [i] .color); //カラーボール[i] .x = balls [i] .Left?ボール[i] .x -10:ボール[i] .x + 10; if(balls [i] .x <0 || balls [i] .x> = this.getWidth()){//水平ボール[i] .left =!balls [i] .left; } balls [i] .y = balls [i] .up?ボール[i] .y -10:ボール[i] .y + 10; if(balls [i] .y <0 || balls [i] .y> = this.getheight()){//方向を垂直方向ボール[i] .up =!balls [i] .up; } g.filloval(balls [i] .x、balls [i] .y、20、20); //指定された直径の円を描く}} //タイムタイム済み実行イベント@override public void actionperformed(actionEvent e){repaint(); // repaint} // focus @override public void foscained(focusevent e){timer.stop(); //タイマーストップ} //失われたフォーカス@Override public void foscolost(focusevent e){timer.restart(); //タイマー再起動}}ballsjframe.java
クラスballsjFrame拡張jframeはchangelistener {private ballscanvas ball;プライベートJspinnerスピナー。 public ballsjframe(){super( "pinball"); this.setbounds(300、200、480、360); this.setDefaultCloseoperation(exit_on_close);色の色[] = {color.red、color.green、color.blue、color.magenta、color.cyan}; Ball =新しいBallScanvas(Colors、100); this.getContentPane()。add(ball); jpanelパネル= new JPanel(); this.getContentPane()。追加(パネル、 "サウス"); panel.add(new Jlabel( "Delay")); spinner = new jspinner(); Spinner.setValue(100); panel.add(スピナー); spinner.addchangelistener(this); this.setVisible(true); } @Override public void stateChanged(ChangeEvent e){// jspinner値を変更する場合、jspinnerのアップまたはダウンボタンをクリックするか、jspinner ball.setdelay(integer.parseint( " + spinner.getvalue()))でEnterを押します。 } public static void main(string [] args){new ballsjframe(); }}効果は次のとおりです。