1. نظرة عامة
تنفيذ وظيفة تنفيذ المهام بانتظام في Java ، وذلك بشكل رئيسي باستخدام فئتين ، Timer و TimerTask فئتين. يتم استخدام الموقت لتنفيذ المهام المحددة في مؤشر ترابط الخلفية وفقًا للخطة المحددة.
Timertask هي فئة مجردة ، وتمثل الفئة الفرعية مهمة يمكن التخطيط لها بواسطة المؤقت. يتم كتابة الرمز المحدد المراد تنفيذه في طريقة التشغيل التي يجب تنفيذ TimerTask.
2. دعونا نلقي نظرة على أبسط مثال
دعنا نشرح ذلك من خلال الكود
استيراد java.text.simpleDateFormat ؛ استيراد java.util.date ؛ استيراد java.util.timer ؛ استيراد java.util.timertask ؛ الطبقة العامة timerdemo {public static string getCurrentTime () {date date = new date () ؛ SimpleDateFormat sdf = جديد simpledateFormat ("Yyyy-MM-DD HH: MM: SS") ؛ إرجاع sdf.format (التاريخ) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException {system.out.println ("Main Start:"+getCurrentTime ()) ؛ startTimer () ؛ thread.sleep (1000*5) ؛ // Sleep لمدة 5 ثوانٍ system.out.println ("Main End:"+getCurrentTime ()) ؛ ) }} ؛ Timer Timer = New Timer () ؛ Timer.Schedule (المهمة ، 0) ؛ }}من أجل تسهيل معلومات المراقبة عن طريق الطباعة ، أضفنا بعض معلومات الطباعة إلى الطريقة الرئيسية ودعا Thread.sleep لجعل نوم الخيط الرئيسي. بالإضافة إلى ذلك ، تتم إضافة طريقة getCurrentTime إلى الفصل للحصول على التاريخ الحالي.
في الكود أعلاه ، في طريقة StartIttimer ، يتم إنشاء كائن TimerTask (المهمة التي سيتم تنفيذها بواسطة المؤقت) ، ويتم إنشاء كائن مؤقت ، ويتم استدعاء طريقة الجدول الزمني لفئة المؤقت. تحتوي فئة المؤقت على طرق جدول متعددة مع معلمات مختلفة. ما هو المستخدم هنا هو:
جدول الفراغ العام (مهمة TimerTask ، تأخير طويل)
معنى هذه الطريقة هو تنفيذ مهمة المهمة بعد أن يؤخر الموقت (ميلي ثانية). إذا كان التأخير سلبيًا أو 0 ، فسيتم تنفيذ المهمة على الفور. وهي مهمة تنفيذ لمرة واحدة ، ولن يتم تكرار المهمة (أو المجدولة) لاحقًا.
بالنسبة لفئة المؤقت ، يتم أيضًا توفير طريقة ذات وظيفة نفسها ، على النحو التالي:
جدول الفراغ العام (مهمة TimerTask ، وقت التاريخ)
الفرق بين هذه الطريقة والطريقة المذكورة أعلاه هو أن الطريقة أعلاه تحدد أن التنفيذ قد تأخر لفترة من الوقت ، وهذه الطريقة تحدد أن التنفيذ يتم في نقطة محددة في الوقت المناسب. لاحظ أنه إذا تجاوز الوقت الحالي للنظام الوقت المحدد في وقت المعلمة ، فسيتم تنفيذ المهمة على الفور.
عند تشغيل الكود أعلاه ، وجدنا أن البرنامج يطبع فورًا مقطعتين من المعلومات مما يلي:
البداية الرئيسية: 2016-01-13 22:23:18
تشغيل المهمة: 2016-01-13 22:23:18
نظرًا لأن قيمة معلمة التأخير التي نمررها إلى طريقة الجدول هنا هي 0 ، سيتم تنفيذ المهمة على الفور ، وبالتالي فإن وقت طباعة البيانين هو نفسه ، وهو ما ينبغي أن يكون. يمكنك تغيير قيمة التأخير الواردة بنفسك لمعرفة التغييرات في معلومات الإخراج. بعد حوالي 5 ثوان (أي وقت النوم) ، واصلت طباعة رسالة واحدة:
الطرف الرئيسي: 2016-01-13 22:23:23
إن وقت طباعة معلومات الطباعة هو أقل من 5 ثوان من البيان أعلاه ، وهو ما يتوافق مع إعداد النوم ، وهو أيضًا معقول للغاية.
لكننا سنجد ظاهرة مثيرة للاهتمام للغاية ، وسوف نجد أن العملية لن تخرج. في هذا الوقت ، انتهى الخيط الرئيسي الرئيسي. هذا يعني أنه بعد أن يكمل الموقت المهمة ، حتى لو لم تكن هناك مهام تنتظر تنفيذها لاحقًا ، فلن يخرج مؤشر ترابط الخلفية الذي تم إنشاؤه في المؤقت على الفور. راجعت وثائق Java Doc ذات الصلة وشرحت أن مؤشر ترابط الموقت لن يخرج بنشاط ويحتاج إلى انتظار جمع القمامة ، ولكن لا يمكن التحكم في جمع القمامة من Java بواسطة الكود نفسه ، ولكن يتم التحكم فيه بواسطة الجهاز الظاهري.
بعد البحث ، تبين أنه عند إنشاء كائن مؤقت وتنفيذ مؤقت مؤقت = توقيت جديد () ؛ بيان ، سيتم إنشاء موضوع المؤقت. بمعنى آخر ، حتى لو لم يكن الرمز أعلاه لا يحتوي على Timer.Schedule (المهمة ، 0) ؛ بيان ، لن يخرج البرنامج. أشعر أن هذا غير معقول للغاية. لقد درست الكود المصدري لفئة المؤقت مرة أخرى ووجدت أنه يحتوي أيضًا على مُنشئ يحتوي على معلمات منطقية:
توقيت عام (منطقي Isdaemon)
كما ترون من اسم المعلمة ، إذا كانت قيمة المعلمة صحيحة ، فإن مؤشر ترابط المؤقت الذي تم إنشاؤه بواسطة Timer هو مؤشر ترابط Daemon. معنى مؤشر ترابط الخفي هو أنه عندما يخرج جميع مؤشرات ترابط العمال في عملية Java ، سيتم الخروج تلقائيًا.
في هذا الوقت ، نحتاج فقط إلى تغيير الكود لإنشاء كائن المؤقت في المثال أعلاه إلى: Timer Timer = New Timer (True) ؛
بعد أن تجد أن البرنامج يتم تشغيله ، سيتم الخروج من البرنامج بعد أن يتم الانتهاء من مؤشر الترابط الرئيسي (لا يكون الخيط الرئيسي مؤشر ترابط خفي ، ولكنه تم إكمال مؤشر ترابط العامل) ، مما يعني أن مؤشر ترابط المؤقت يخرج أيضًا ، مما يعني أنه بعد إضافة المعلمة True ، يكون مؤشر ترابط الخنق الذي تم إنشاؤه هو مؤشر ترابط Daemon.
ولكن المشكلة هي أنه في سيناريوهات التطبيق الحقيقية ، هناك العديد من مؤشرات الترابط العاملة التي تعمل ولن يخرج البرنامج بشكل عرضي. فماذا لو كنت تريد أن يخرج المؤقت أو يغلق على الفور؟ سنقدم هذا أدناه.
3. خروج المؤقت
توفر فئة المؤقت طريقة إلغاء لإلغاء المؤقت. سيقوم استدعاء طريقة الإلغاء بإنهاء هذا الموقت وتجاهل جميع المهام المجدولة حاليًا. هذا لا يتداخل مع المهمة المنفذة حاليًا (إذا كانت موجودة). بمجرد إنهاء المؤقت ، سينتهي مؤشر ترابط التنفيذ الخاص به أيضًا ولا يمكن تحديد مزيد من المهام وفقًا لذلك.
لاحظ أنه من خلال استدعاء هذه الطريقة داخل طريقة التشغيل لمهمة المؤقت المسمى هذا المؤقت ، يمكنك التأكد تمامًا من أن المهمة التي يتم تنفيذها هي المهمة الأخيرة التي تنفذها هذا المؤقت. يمكن استدعاء هذه الطريقة بشكل متكرر ؛ ومع ذلك ، فإن المكالمات الثانية واللاحقة غير صالحة.
دعونا نلقي نظرة على رمز مثال آخر:
استيراد java.text.simpleDateFormat ؛ استيراد java.util.date ؛ استيراد java.util.timer ؛ استيراد java.util.timertask ؛ الطبقة العامة timerdemo {public static string getCurrentTime () {date date = new date () ؛ SimpleDateFormat sdf = جديد simpledateFormat ("Yyyy-MM-DD HH: MM: SS") ؛ إرجاع sdf.format (التاريخ) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException {system.out.println ("Main Start:"+getCurrentTime ()) ؛ Timer Timer = startTimer () ؛ thread.sleep (1000*5) ؛ // Sleep لمدة 5 ثوانٍ system.out.println ("Main End:"+getCurrentTime ()) ؛ Timer.Cancel () ؛ } public static timer startTimer () {timertask task = new timertask () {Override public void run () {system.out.println ("Task Run:"+getCurrentTime ()) ؛ }} ؛ Timer Timer = New Timer () ؛ Timer.Schedule (المهمة ، 0) ؛ عودة المؤقت }} تشغيل البرنامج هو بالضبط نفس إخراج المثال أعلاه. الفرق هو أنه عندما تنتهي الطريقة الرئيسية. ستخرج العملية بنشاط ، مما يعني أنه تم إغلاق موضوع المؤقت.
لأننا نسمي طريقة الإلغاء في الطريقة الرئيسية. لاحظ أنه إذا لم تكن تتصل بطريقة الإلغاء في طريقة تشغيل TimerTask ، فتأكد من التأكد من أن المهمة التي تريد تنفيذها قد بدأت أو اكتملت ، وإلا إذا لم تبدأ المهمة في التنفيذ. ما عليك سوى استدعاء إلغاء ، ولن يتم تنفيذ جميع المهام. على سبيل المثال ، الرمز أعلاه ،
على سبيل المثال ، في الكود أعلاه ، إذا لم نتصل بالطريقة إلغاء في الطريقة الرئيسية ، ولكن أضف timer.schedule (المهمة ، 0) ؛ بيان في طريقة startTimer وأضف timer.cancel () ؛ بيان بعد التشغيل ، ستجد أنه لن يتم تنفيذ مهمة المؤقت ، لأنه سيتم إلغاؤها قبل اكتمال التنفيذ.
4. تنفيذ المهام بانتظام
في المثال أعلاه ، نقدم مهمة لمرة واحدة ، أي أن الوقت قد حان. بعد تنفيذ المهمة ، لن يتم تكرارها لاحقًا. في التطبيقات الفعلية ، هناك العديد من السيناريوهات التي تتطلب تنفيذ المهمة نفسها بشكل منتظم بشكل منتظم. هناك حالتان: أحدهما هو تنفيذ المهام كل مرة من حين إلى آخر ، والآخر هو أداء المهام في نقاط زمنية (أو عدة) كل يوم (أو أسبوعيًا ، شهريًا ، إلخ).
دعونا أولاً نلقي نظرة على الحالة الأولى ، وهي مثال على تنفيذ نفس المهمة كل 10 ثوانٍ. الرمز كما يلي:
استيراد java.text.simpleDateFormat ؛ استيراد java.util.date ؛ استيراد java.util.timer ؛ استيراد java.util.timertask ؛ الطبقة العامة timerdemo {public static string getCurrentTime () {date date = new date () ؛ SimpleDateFormat sdf = جديد simpledateFormat ("Yyyy-MM-DD HH: MM: SS") ؛ إرجاع sdf.format (التاريخ) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException {system.out.println ("Main Start:"+getCurrentTime ()) ؛ startTimer () ؛ ) حاول {thread.sleep (1000*3) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}} ؛ Timer Timer = New Timer () ؛ Timer.Schedule (المهمة ، 1000*5،1000*10) ؛ }} قم بتنفيذ البرنامج أعلاه ومعلومات الإخراج على النحو التالي (لأن المؤقت لا يتوقف ، ويتكرر المهمة ، وسيتم إخراج الإخراج بشكل مستمر. يتم نسخ بعض المخرجات السابقة فقط هنا)
البداية الرئيسية: 2016-01-14 08:41:14
تشغيل المهمة: 2016-01-14 08:41:19
تشغيل المهمة: 2016-01-14 08:41:29
تشغيل المهمة: 2016-01-14 08:41:39
تشغيل المهمة: 2016-01-14 08:41:49
تشغيل المهمة: 2016-01-14 08:42:00
تشغيل المهمة: 2016-01-14 08:42:10
تشغيل المهمة: 2016-01-14 08:42:20
تشغيل المهمة: 2016-01-14 08:42:30
تشغيل المهمة: 2016-01-14 08:42:40
في الكود أعلاه ، ندعو timer.schedule (المهمة ، 1000*5،1000*10) ؛ هذا يعني أن المهمة تتأخر بمقدار 5 ثوان ، وبعد ذلك سيتم تكرارها كل 10 ثوان. نلاحظ أن وقت الطباعة في معلومات الإخراج هو نفسه كما هو متوقع. بالإضافة إلى ذلك ، يمكن ملاحظة أن الفاصل الزمني محسوب بناءً على وقت بدء المهمة ، أي أنه لا ينتظر 10 ثوانٍ أخرى بعد اكتمال المهمة.
لدى فئة المؤقت طريقتان لتنفيذ هذه الوظائف ، على النحو التالي:
جدول الفراغ العام (مهمة TimerTask ، تأخير طويل ، فترة طويلة) جدول الفراغ العام (مهمة TimerTask ، التاريخ الأول ، الفترة الطويلة)
الطريقة الأولى التي نستخدمها أعلاه. الفرق بين الطريقتين هو وقت التنفيذ الأول. يتم تنفيذ الطريقة الأولى بعد تأخير محدد لفترة زمنية (بالميلي ثانية) ؛ يتم تنفيذ الطريقة الثانية في نقطة زمنية محددة.
في هذا الوقت ، نعتبر السيناريو التالي. إذا تجاوز وقت تنفيذ المهمة وقت الانتظار التالي ، فماذا سيحدث؟ دعونا نلقي نظرة عليه من خلال الكود:
استيراد java.text.simpleDateFormat ؛ استيراد java.util.date ؛ استيراد java.util.timer ؛ استيراد java.util.timertask ؛ الطبقة العامة timerdemo {public static string getCurrentTime () {date date = new date () ؛ SimpleDateFormat sdf = جديد simpledateFormat ("Yyyy-MM-DD HH: MM: SS") ؛ إرجاع sdf.format (التاريخ) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException {system.out.println ("Main Start:"+getCurrentTime ()) ؛ startTimer () ؛ } public static void startTimer () {timertask task = new timertask () {Override public void run () {system.out.println ("Task Begin:"+getCurrentTime ()) ؛ حاول {thread.sleep (1000*10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } system.out.println ("نهاية المهمة:"+getCurrentTime ()) ؛ }} ؛ Timer Timer = New Timer () ؛ Timer.Schedule (المهمة ، 1000*5،1000*5) ؛ }} مقارنة بالرمز السابق ، قمنا بتغيير رموز 2 فقط وقمنا بتعديل الطباعة. أحدهما هو تغيير النوم في طريقة التشغيل إلى 10 ثوان ، والآخر هو تغيير دورة التنفيذ للمهمة إلى 5 ثوان. بمعنى آخر ، يتجاوز وقت تنفيذ المهمة الفاصل بين التنفيذ المتكرر للمهمة. تشغيل البرنامج ، الإخراج السابق هو كما يلي:
البداية الرئيسية: 2016-01-14 09:03:51
المهمة تبدأ: 2016-01-14 09:03:56
نهاية المهمة: 2016-01-14 09:04:06
المهمة تبدأ: 2016-01-14 09:04:06
نهاية المهمة: 2016-01-14 09:04:16
المهمة تبدأ: 2016-01-14 09:04:16
نهاية المهمة: 2016-01-14 09:04:26
المهمة تبدأ: 2016-01-14 09:04:26
نهاية المهمة: 2016-01-14 09:04:36
بداية المهمة: 2016-01-14 09:04:36
نهاية المهمة: 2016-01-14 09:04:46
المهمة تبدأ: 2016-01-14 09:04:46
نهاية المهمة: 2016-01-14 09:04:56
يمكن ملاحظة أنه بعد تنفيذ كل مهمة ، سيتم تنفيذ المهمة التالية على الفور. لأن الوقت المستغرق من بداية المهمة إلى الانتهاء من المهمة قد تجاوز الفاصل الزمني بين تكرار المهمة ، سيتم تكرار التنفيذ.
5. تنفيذ المهام بانتظام (كرر النقطة الزمنية الثابتة)
دعنا ننفذ مثل هذه الوظيفة ، وننفذ مهمة بانتظام في الساعة الواحدة صباحًا كل يوم ، والتي لديها هذه الوظيفة في العديد من الأنظمة ، مثل إكمال المهام التي تستغرق وقتًا طويلاً وتستهلك الموارد مثل النسخ الاحتياطي للبيانات وإحصائيات البيانات في هذه المهمة. الرمز كما يلي:
استيراد java.text.simpleDateFormat ؛ استيراد java.util.calendar ؛ استيراد java.util.date ؛ استيراد java.util.timer ؛ استيراد java.util.timertask ؛ timerdemo من الفئة العامة SimpleDateFormat sdf = جديد simpledateFormat ("Yyyy-MM-DD HH: MM: SS") ؛ إرجاع sdf.format (التاريخ) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException {system.out.println ("Main Start:" + getCurrentTime ()) ؛ startTimer () ؛ } public static void startTimer () {timertask task = new timertask () {Override public void run () {system.out.println ("Task Begin:" + getCurrentTime ()) ؛ حاول {thread.sleep (1000 * 20) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } system.out.println ("نهاية المهمة:" + getCurrentTime ()) ؛ }} ؛ Timer Timer = New Timer () ؛ Timer.Schedule (Task ، BuildTime () ، 1000 * 60 * 60 * 24) ؛ } private static date buildtime () {calendar calendar = calendar.getInstance () ؛ Calendar.set (Calendar.hour_of_day ، 1) ؛ Calendar.set (Calendar.minute ، 0) ؛ Calendar.set (Calendar.Second ، 0) ؛ تاريخ التاريخ = calendar.getTime () ؛ if (time.beore (date date ())) {// إذا كان الوقت الحالي بعد الساعة الواحدة صباحًا ، فستكون هناك حاجة إلى يوم واحد ، وإلا سيتم تنفيذ المهمة على الفور. // غالبًا ما تحتاج العديد من الأنظمة إلى تنفيذ المهام فورًا عند بدء تشغيل النظام ، لكنهم بحاجة إلى تنفيذها في الساعة الواحدة صباحًا كل يوم. ماذا علي أن أفعل؟ // الأمر بسيط للغاية ، فقط قم بتنفيذ المهمة بشكل منفصل عندما يقوم النظام بتهيئة المكالمة (لا يلزم وجود مؤقت ، فهو مجرد رمز لتنفيذ هذه المهمة) الوقت = AddDay (الوقت ، 1) ؛ } وقت العودة ؛ } Addday Date static الخاص (تاريخ التاريخ ، int) {calendar startDt = calendar.getInstance () ؛ StartDt.Settime (Date) ؛ StartDt.add (Calendar.day_of_month ، Days) ؛ return startdt.getTime () ؛ }}نظرًا لأنه يتم تنفيذه على فترات مدتها 24 ساعة ، فمن المستحيل انتظار مراقبة الإخراج.
6. ملخص
تقدم هذه المقالة آلية كيفية أداء المهام المحددة باستخدام فئة Java Timer. يمكن ملاحظة أنه لا يزال هناك العديد من الطرق للانتباه إليها. في الأمثلة التي تم تقديمها في هذه المقالة ، يتوافق كل مؤقت مع مهمة واحدة فقط.
يمكن للمحتوى الذي تم تقديمه في هذه المقالة تلبية معظم سيناريوهات التطبيق ، ولكن لا تزال هناك بعض المشكلات ، مثل تضمين مهام متعددة لمؤقت؟ هل يمكنني إضافة مهام مرة أخرى بعد إلغاء المؤقت؟ ما هي الطرق الأخرى المتوفرة في فئة المؤقت؟ سيتم تقديم هذه الأسئلة في منشور المدونة التالي.
الرابط الأصلي: http://www.cnblogs.com/51kata/p/5128745.html
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.