إذا كنا بحاجة إلى تنفيذ بعض مهام التوقيت البسيطة أثناء عملية البرمجة الخاصة بنا ، فلن نحتاج إلى تحكم معقد. يمكننا التفكير في استخدام مهام توقيت المؤقت في JDK لتحقيق ذلك. تقوم LZ التالية بتحليل Timer Java Timer بناءً على مبدأها ومثالها وعيوب المؤقت.
1. مقدمة
في Java ، يجب إكمال مهمة التوقيت الكاملة بواسطة فئات Timer و TimerTask. هذه هي الطريقة التي يتم تعريفها في API. المؤقت: أداة تستخدمها لترتيب المهام التي تؤديها مؤشرات الترابط في مؤشرات ترابط الخلفية لاحقًا. يمكن تنفيذ المهام مرة واحدة ، أو يمكن تنفيذها بشكل متكرر. المهمة التي تم تحديدها بواسطة TimerTask: Timer كمهمة يتم تنفيذها أو تكرارها. يمكننا أن نفهم أن المؤقت هو أداة مؤقت تستخدم لتنفيذ المهام المحددة في موضوع خلفية ، و timertask فئة مجردة تمثل فئة الفرعية مهمة يمكن تخطيطها بواسطة المؤقت.
Timer Class <BR /> في Tool Class Timer ، يتم توفير أربع طرق مُنشأة. يبدأ كل مُنشئ مؤشر ترابط مؤقت. في الوقت نفسه ، يمكن لفئة المؤقتة التأكد من أن مؤشرات الترابط المتعددة يمكنها مشاركة كائن مؤقت واحد دون مزامنة خارجي ، وبالتالي فإن فئة الموقت آمنة مؤشرات الترابط. ومع ذلك ، نظرًا لأن كل كائن مؤقت يتوافق مع مؤشر ترابط خلفية واحد ، والذي يتم استخدامه لتنفيذ جميع مهام الموقت بالتسلسل ، بشكل عام ، يجب أن يكون الوقت الذي يقضيه في تنفيذ مهمة مؤشر ترابطنا قصيرة للغاية. ومع ذلك ، نظرًا للظروف الخاصة ، فإن وقت تنفيذ مهمة مؤقت معينة طويلة جدًا ، لذلك سوف "حصريًا" مؤشر ترابط تنفيذ المهام الموقت ، ويجب أن تنتظر جميع المواضيع اللاحقة حتى يتم تنفيذها ، مما سيؤخر تنفيذ المهام اللاحقة وجعل هذه المهام تتراكم معًا. سنقوم بتحليل الوضع المحدد لاحقًا.
عندما يقوم البرنامج بتهيئة المؤقت ، سيتم تنفيذ مهمة التوقيت وفقًا للوقت الذي حددناه. يوفر Timer طريقة الجدول الزمني ، الذي يحتوي على العديد من الأحمال الزائدة للتكيف مع المواقف المختلفة ، على النحو التالي:
الجدول الزمني (مهمة TimerTask ، وقت التاريخ): جدولة تنفيذ المهمة المحددة في الوقت المحدد.
الجدول الزمني (مهمة TimerTask ، التاريخ الأول ، الفترة الطويلة): جدولة المهمة المحددة لبدء تنفيذ التأخير الثابت المتكرر في الوقت المحدد.
الجدول الزمني (مهمة TimerTask ، تأخير طويل): يحدد المهمة المحددة التي سيتم تنفيذها بعد التأخير المحدد.
الجدول الزمني (مهمة TimerTask ، التأخير الطويل ، الفترة الطويلة): جدولة المهمة المحددة المراد تنفيذها ثابتة بشكل متكرر بعد التأخير المحدد.
في الوقت نفسه ، يتم أيضًا تحميل طريقة ScheduleAtFixedRate. طريقة ScheduleAtFixedRate هي نفس الجدول الزمني ، ولكن تركيزها مختلف ، ويتم تحليل الفرق لاحقًا.
ScheduleAtfixedRate (مهمة TimerTask ، التاريخ الأول ، الفترة الطويلة): حدد موعدًا للمهمة المحددة المراد تنفيذها بشكل متكرر بمعدل ثابت في وقت محدد.
ScheduleAtFixedRate (مهمة TimerTask ، التأخير الطويل ، الفترة الطويلة): جدولة المهمة المحددة لبدء تنفيذ معدل ثابت متكرر بعد التأخير المحدد.
Timertask
فئة TimerTask هي فئة مجردة ترتيبها المؤقت كمهمة يتم تنفيذها أو تكرارها. يحتوي على طريقة تجريدية Run () ، والتي يتم استخدامها لتنفيذ العمليات التي ستتم تنفيذها بواسطة مهمة المؤقت المقابلة. لذلك ، يجب أن ترث كل فئة مهمة محددة timertask ثم تجاوز طريقة التشغيل ().
بالإضافة إلى ذلك ، يحتوي على طريقتان غير متجانسة:
Boolean Cancel (): قم بإلغاء مهمة المؤقت هذه.
Long SchedeDexecutionTime (): إرجاع وقت التنفيذ المجدول لأحدث تنفيذ فعلي لهذه المهمة.
2. أمثلة
2.1. حدد وقت التأخير لتنفيذ مهام التوقيت
الطبقة العامة TimerTest01 {Timer Timer ؛ mimertest01 (int time) {timer = new timer () ؛ Timer.Schedule (New TimerTaskTest01 () ، time * 1000) ؛ } public static void main (string [] args) {system.out.println ("Timer Begin ...") ؛ New TimerTest01 (3) ؛ }} الفئة العامة TimerTaskTest01 يمتد timertask {public void run () {system.out.println ("time's up !!!") ؛ }} نتائج التشغيل:
الطباعة الأولى: بدء المؤقت ...
طباعة في 3 ثوان: الوقت يصل !!!
2.2. تنفيذ مهام التوقيت في الوقت المحدد
الطبقة العامة TimerTest02 {Timer Timer ؛ public mimertest02 () {date time = getTime () ؛ System.out.println ("حدد time time =" + time) ؛ Timer = New Timer () ؛ Timer.Schedule (New TimerTaskTest02 () ، time) ؛ } التاريخ العام getTime () {Calendar Calendar = calendar.getInstance () ؛ Calendar.set (Calendar.hour_of_day ، 11) ؛ Calendar.set (Calendar.Minute ، 39) ؛ Calendar.set (Calendar.Second ، 00) ؛ تاريخ التاريخ = calendar.getTime () ؛ وقت العودة } public static void main (string [] args) {new TimerTest02 () ؛ }} الفئة العامة TimerTaskTest02 يمتد timertask {Override public void run () {system.out.println ("تنفيذ مهام مؤشر الترابط في الوقت المحدد ...") ؛ }} عندما يصل الوقت إلى الساعة 11:39:00 ، سيتم تنفيذ مهمة الخيط ، بالطبع ، سيتم تنفيذها حتى لو كانت أكبر من ذلك الوقت! ! نتيجة التنفيذ هي:
الوقت المحدد = الثلاثاء 10 يونيو 11:39:00 CST 2014
تنفيذ مهام سلسلة الرسائل في الوقت المحدد ...
2.3. بعد تأخير الوقت المحدد ، سيتم تنفيذ مهمة التوقيت في وقت الفاصل الزمني المحدد.
الطبقة العامة TimerTest03 {Timer Timer ؛ public mimertest03 () {timer = new timer () ؛ Timer.Schedule (New TimerTaskTest03 () ، 1000 ، 2000) ؛ } public static void main (string [] args) {new TimerTest03 () ؛ }} الفئة العامة timertasktest03 يمتد timertask {Override public void run () {date date = new date (this.scheduledExecutionTime ()) ؛ System.out.println ("وقت تنفيذ هذا الموضوع هو:" + تاريخ) ؛ }} نتائج التشغيل:
وقت تنفيذ هذا الموضوع هو: Tue Jun 10 21:19:47 CST 2014
وقت تنفيذ هذا الموضوع هو: Tue Jun 10 21:19:49 CST 2014
وقت تنفيذ هذا الموضوع هو: Tue 10 Jun 10 21:19:51 CST 2014
وقت تنفيذ هذا الموضوع هو: Tue 10 Jun 10 21:19:53 CST 2014
وقت تنفيذ هذا الموضوع هو: Tue 10 Jun 10 21:19:55 CST 2014
وقت تنفيذ هذا الموضوع هو: Tue Jun 10 21:19:57 CST 2014
................
بالنسبة لمهمة الموضوع هذه ، إذا لم نتوقف عن المهمة ، فسيستمر تشغيلها.
بالنسبة للأمثلة الثلاثة المذكورة أعلاه ، أظهرت LZ ذلك لفترة وجيزة ، ولم تشرح مثال طريقة ScheduleAtFixedRate. في الواقع ، هذه الطريقة هي نفس طريقة الجدول!
2.4. تحليل الجدول الزمني و ScheduleAtfixedrate
1) ، الجدول الزمني (مهمة TimerTask ، وقت التاريخ) ، الجدول الزمني (مهمة TimerTask ، تأخير طويل)
بالنسبة لكلتا الطريقتين ، إذا كان SchedeDexecutionTime المحدد <= SystemCurrentTime ، فسيتم تنفيذ المهمة على الفور. لن يتغير SignedExecutionTime بسبب التنفيذ المفرط للمهمة.
2) الجدول الزمني (مهمة TimerTask ، التاريخ الأول ، الفترة الطويلة) ، الجدول الزمني (مهمة TimerTask ، تأخير طويل ، فترة طويلة)
هاتان الطريقتان مختلفتان بعض الشيء عن اثنين أعلاه. كما ذكرنا سابقًا ، سيتم تأخير مهمة مؤقت المؤقت لأن المهمة السابقة يتم تنفيذها لفترة طويلة. في هاتين الطريقتين ، سيتغير الوقت المحدد لكل مهمة تم تنفيذه مع الوقت الفعلي للمهمة السابقة ، أي أن enderedExecutionTime (n+1) = relexecutiontime (n)+time. وهذا يعني ، إذا تسببت المهمة التاسعة في عملية وقت التنفيذ هذه بسبب بعض المواقف ، وأخيراً SystemCurrentTime> = SchedeDexecutionTime (n+1) ، فهذه هي المهمة N+1 ولن يتم تنفيذها بسبب الوقت. ستنتظر تنفيذ المهمة التاسعة قبل التنفيذ ، ثم سيؤدي ذلك حتماً إلى إصدار تنفيذ N+2 SchedeDexecutionTime وتغييره ، أي أن الوقت ScheduledExecutionTime (N+2) = فترة التأمل (N+1)+فترة. لذلك ، تولي هاتان الطريقتان المزيد من الاهتمام لاستقرار وقت التخزين.
3) SCHEDULEATFIXEDRATE (مهمة TIMERTASK ، التاريخ الأول ، الفترة الطويلة) ، SCHEDULEATFIXEDRATE (مهمة TIMERTASK ، تأخير طويل ، فترة طويلة)
كما ذكرنا سابقًا ، فإن تركيز طرق ScheduleAtfixedrate وجدوله مختلف. تركز طريقة الجدول الزمني على استقرار وقت الادخار ، بينما تركز طريقة ScheduleAtFixedRate بشكل أكبر على الحفاظ على استقرار تردد التنفيذ. لماذا تقول ذلك ، الأسباب هي كما يلي. في طريقة الجدول الزمني ، سوف يتسبب تأخير المهمة السابقة في تأخير مهمة التوقيت بعد ذلك ، في حين أن طريقة ScheduleAtFixedRate لن تفعل ذلك. إذا كان وقت التنفيذ للمهمة التاسعة طويلة جدًا ، فإن SystemCurrentTime> = SchededExecutionTime (N+1) ، فلن يكون هناك انتظار لتنفيذ مهمة N+1 على الفور. لذلك ، تختلف طريقة الحساب لوقت تنفيذ طريقة ScheduleAtFixedRate عن الجدول الزمني ، ولكن ScheduleDexecutionTime (n) = FirstExecuteTime +N*فترة ، وستظل طريقة الحساب لم تتغير إلى الأبد. لذلك يركز ScheduleAtFixedRate أكثر على الحفاظ على تردد التنفيذ مستقر.
3. عيوب الموقت
3.1. عيوب المؤقت
يمكن لوقت المؤقت الوقت (تنفيذ المهام في الوقت المحدد) ، والتأخير (مهام التأخير في 5 ثوان) ، وتنفيذ المهام بشكل دوري (تنفيذ المهام في ثانية واحدة) ، ولكن الموقت لديه بعض أوجه القصور. بادئ ذي بدء ، يعتمد دعم المؤقت للجدولة على الوقت المطلق ، وليس الوقت النسبي ، لذلك فهو حساس للغاية للتغيرات في وقت النظام. ثانياً ، لن يلتقط موضوع المؤقت استثناءات. إذا تم إلقاء الاستثناء غير المحدد بواسطة TimerTask ، فسوف يتسبب ذلك في إنهاء مؤشر ترابط المؤقت. في الوقت نفسه ، لن يستأنف المؤقت تنفيذ مؤشر الترابط ، وسيؤمن عن طريق الخطأ أنه سيتم إلغاء مؤشر ترابط المؤقت بالكامل. في الوقت نفسه ، لن يتم تنفيذ TimerTask ، التي تم تحديد موعد لمقدمها بعد ، ولا يمكن جدولة مهام جديدة. لذلك ، إذا قام Timertask بإلقاء استثناء غير محدد ، فإن المؤقت سوف ينتج سلوكًا لا يمكن التنبؤ به.
1) عيب تأخير وقت إدارة المؤقت <BR /> سيقوم المؤقت السابق بإنشاء مهمة مؤشر ترابط واحدة فقط عند تنفيذ مهمة محددة الوقت. إذا كان هناك عدة مؤشرات ترابط ، إذا تسبب إحدى مؤشرات الترابط في وقت تنفيذ مهمة مؤشر الترابط لتكون طويلة جدًا لسبب ما ، وتجاوز الفاصل بين المهمتين الوقت بينهما ، ستحدث بعض العيوب:
الطبقة العامة timertest04 {private timer timer ؛ بداية طويلة عامة ؛ public mimertest04 () {this.timer = new timer () ؛ start = system.currentTimeMillis () ؛ } public void timerOne () {timer.schedule (new timertask () {public void run () {system.out.println ("timerone ادعاء ، الوقت: }}}} ، 1000) ؛ } public void timertwo () {timer.schedule (new timertask () {public void run () {system.out.println ( } public static void main (string [] args) يلقي الاستثناء {timertest04 test = new timertest04 () ؛ test.timerone () ؛ test.timertwo () ؛ }} وفقًا لتفكيرنا الطبيعي ، يجب تنفيذ Timertwo بعد 3s ، ويجب أن تكون النتيجة:
تم استدعاء Timerone ، الوقت: 1001
تم استدعاء Timerone ، الوقت: 3001
لكن الأمور تتعارض مع توقعاتي. Timerone Sleeps (4000) ، ينام 4s ، والوقت داخل المؤقت ، والذي يسبب الوقت اللازم لـ TimeOne لتجاوز الفاصل الزمني. النتيجة:
تم استدعاء Timerone ، الوقت: 1000
تم استدعاء Timerone ، الوقت: 5000
2) توقيت يلقي عيب الاستثناء
إذا قام TimerTask بإلقاء RunTimeException ، فسيقوم المؤقت بإنهاء جميع المهام. على النحو التالي:
الطبقة العامة timertest04 {private timer timer ؛ public mimertest04 () {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.
استثناء في الموضوع "Timer-0" java.lang.runtimeexception في com.chenssy.timer.timertest04 $ 1.run (timertest04.java:25) على java.util.timerthread.mainloop (timer.java:555) على java.util.timerthread.run.
بالنسبة لعيوب الموقت ، يمكننا النظر في SecrettHreadPoolexecutor كبديل. يعتمد المؤقت على الوقت المطلق وهو أكثر حساسية لوقت النظام ، في حين أن ScredulThreadPoolexecutor يعتمد على الوقت النسبي ؛ Timer عبارة عن مؤشر ترابط واحد داخليًا ، في حين أن ScurdeThreadPoolexecutor هو تجمع مؤشرات ترابط داخليًا ، بحيث يمكنه دعم التنفيذ المتزامن لمهام متعددة.
3.2. استبدال المؤقت مع SchedeDexecutorService
1) حل المشكلة الأولى:
فئة عامة Schedulexecutortest {private ScredeDexecutorService Scheduexec ؛ بداية طويلة عامة ؛ ScheduleDexecutortest () {this.scheduexec = evelopors.newsCheduleDthReadPool (2) ؛ this.start = system.currentTimeMillis () ؛ } public void timerOne () {scheduexec.schedule (new RunNable () {public void run () {system.out.println ("timeerOne ، time:" + (system.currentTimeMillis () - start)) ؛ try {thread.sleep (4000) ؛ } ، 1000 ، timeunit.milliseconds) ؛ } public void timertwo () {ScheduleExec.Schedule (new RunNable () {public void run () {system.out.println ("timertwo ، time:" + (system.currenttimeMillis () - start)) ؛}} ، 2000 ، timeunit.milliseconds) ؛ } public static void main (string [] args) {ScrededExecutortest test = new ScheduleDexecutortest () ؛ test.timerone () ؛ test.timertwo () ؛ }} نتائج التشغيل:
Timerone ، الوقت: 1003
تيميرتو ، الوقت: 2005
2) حل المشكلة اثنين
فئة عامة Schedulexecutortest {private ScredeDexecutorService Scheduexec ؛ بداية طويلة عامة ؛ ScheduleDexecutortest () {this.scheduexec = evelopors.newsCheduleDthReadPool (2) ؛ this.start = system.currentTimeMillis () ؛ } public void timerOne () {scheduexec.schedule (new RunNable () {public void run () {throw new RunTimeException () ؛}} ، 1000 ، timeunit.milliseconds) ؛ } public void timertwo () {ScheduleExec.ScheDuleAtfixedRate (new RunNable () {public void run () {system.out.println ("Timertwo invoked .....") ؛}} ، 2000،500 ، timunit.milliseconds) ؛ } public static void main (string [] args) {ScrededExecutortest test = new ScheduleDexecutortest () ؛ test.timerone () ؛ test.timertwo () ؛ }} نتائج التشغيل:
تم استدعاء Timertwo ... استدعى Timertwo ... Timertwo استدعى ... Timertwo استدعى ... Timertwo استدعى ... Timertwo استدعى ... Timertwo استدعاء ...
ما سبق هو المحتوى الكامل لهذه المقالة. هذا كل شيء عن مهام توقيت جافا. آمل أن يكون مفيدًا لتعلمك.